Vztahy typů v operacích dotazu LINQ (C#)

Pokud chcete efektivně psát dotazy, měli byste porozumět tomu, jak typy proměnných v celé operaci dotazu vzájemně souvisejí. Pokud těmto relacím rozumíte, snadněji pochopíte ukázky LINQ a příklady kódu v dokumentaci. Dále pochopíte, co se stane, když jsou proměnné implicitně zadány pomocí .var

Operace dotazů LINQ jsou silně zadané ve zdroji dat, v samotném dotazu a při provádění dotazu. Typ proměnných v dotazu musí být kompatibilní s typem prvků ve zdroji dat a s typem proměnné iterace v foreach příkazu. Tento silný typ zaručuje, že chyby typu jsou zachyceny v době kompilace, když je lze opravit, než se na ně uživatelé dostanou.

Aby bylo možné tyto relace typů předvést, většina příkladů, které následují, používají explicitní psaní pro všechny proměnné. Poslední příklad ukazuje, jak stejné principy platí i při použití implicitního psaní pomocí var.

Dotazy, které transformují zdrojová data

Následující obrázek znázorňuje operaci dotazu LINQ to Objects, která neprovádí žádné transformace dat. Zdroj obsahuje posloupnost řetězců a výstup dotazu je také posloupnost řetězců.

Diagram znázorňující vztah datových typů v dotazu LINQ

  1. Argument typu zdroje dat určuje typ proměnné rozsahu.
  2. Typ vybraného objektu určuje typ proměnné dotazu. Tady name je řetězec. Proto je proměnná dotazu .IEnumerable<string>
  3. Proměnná dotazu se v foreach příkazu iteuje. Vzhledem k tomu, že proměnná dotazu je posloupnost řetězců, je proměnná iterace také řetězec.

Dotazy, které transformují zdrojová data

Následující obrázek znázorňuje operaci dotazu LINQ to SQL, která provádí jednoduchou transformaci dat. Dotaz přebírá posloupnost Customer objektů jako vstup a vybere pouze Name vlastnost ve výsledku. Protože Name je řetězec, dotaz vytvoří posloupnost řetězců jako výstup.

Diagram znázorňující dotaz, který transformuje datový typ

  1. Argument typu zdroje dat určuje typ proměnné rozsahu.
  2. Příkaz select vrátí Name vlastnost místo kompletního Customer objektu. Protože Name je řetězec, typ argumentu custNameQuery je string, nikoli Customer.
  3. Vzhledem k tomucustNameQuery, že je posloupnost řetězců, foreach musí být iterační proměnná smyčky také .string

Následující obrázek znázorňuje o něco složitější transformaci. Příkaz select vrátí anonymní typ, který zachycuje pouze dva členy původního Customer objektu.

Diagram znázorňující složitější dotaz, který transformuje datový typ

  1. Argument typu zdroje dat je vždy typem proměnné rozsahu v dotazu.
  2. Protože příkaz select vytvoří anonymní typ, musí být proměnná dotazu implicitně zadána pomocí .var
  3. Vzhledem k tomu, že typ proměnné dotazu je implicitní, musí být implicitní i iterační proměnná ve foreach smyčce.

Umožňuje kompilátoru odvodit informace o typu.

I když byste měli porozumět relacím typů v operaci dotazu, máte možnost, aby kompilátor udělal všechno za vás. Klíčové slovo var lze použít pro libovolnou místní proměnnou v operaci dotazu. Následující obrázek je podobný příkladu čísla 2, který jsme probrali dříve. Kompilátor však poskytuje silný typ pro každou proměnnou v operaci dotazu.

Diagram znázorňující tok typu s implicitními psaními

LINQ a obecné typy (C#)

Dotazy LINQ jsou založené na obecných typech. Než začnete psát dotazy, nepotřebujete podrobné znalosti obecných typů. Možná ale budete chtít porozumět dvěma základním konceptům:

  1. Když vytvoříte instanci obecné třídy kolekce, například List<T>, nahradíte "T" typem objektů, které bude seznam obsahovat. Například seznam řetězců je vyjádřen jako List<string>a seznam Customer objektů je vyjádřen jako List<Customer>. Obecný seznam je silného typu a poskytuje mnoho výhod oproti kolekcí, které ukládají jejich prvky jako Object. Pokud se pokusíte přidat do objektu CustomerList<string>, zobrazí se chyba v době kompilace. Je snadné používat obecné kolekce, protože nemusíte provádět přetypování typu za běhu.
  2. IEnumerable<T> je rozhraní, které umožňuje výčet obecných tříd kolekcí pomocí foreach příkazu. Obecné třídy kolekce podporují IEnumerable<T> stejně jako obecné třídy kolekce, jako ArrayList je podpora IEnumerable.

Další informace o obecných typů najdete v tématu Obecné typy.

Proměnné T> IEnumerable<v dotazech LINQ

Proměnné dotazu LINQ jsou zadány jako IEnumerable<T> nebo odvozený typ, například IQueryable<T>. Když uvidíte proměnnou dotazu, která je zadáváná jako IEnumerable<Customer>, znamená to, že dotaz při jeho spuštění vytvoří sekvenci nulových nebo více Customer objektů.

IEnumerable<Customer> customerQuery =
    from cust in customers
    where cust.City == "London"
    select cust;

foreach (Customer customer in customerQuery)
{
    Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}

Umožňuje kompilátoru zpracovávat deklarace obecného typu.

Pokud chcete, můžete se vyhnout obecné syntaxi pomocí klíčového slova var . Klíčové var slovo dává kompilátoru pokyn, aby odvodil typ proměnné dotazu tak, že se podívá na zdroj dat zadaný v from klauzuli. Následující příklad vytvoří stejný zkompilovaný kód jako předchozí příklad:

var customerQuery2 =
    from cust in customers
    where cust.City == "London"
    select cust;

foreach(var customer in customerQuery2)
{
    Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}

Klíčové var slovo je užitečné, když je typ proměnné zřejmý nebo pokud není důležité explicitně zadat vnořené obecné typy, jako jsou ty, které jsou vytvářeny pomocí skupinových dotazů. Obecně doporučujeme, abyste pokud používáte var, uvědomte si, že může váš kód ztížit čtení ostatních. Další informace naleznete v tématu Implicitně typované místní proměnné.