Relacje typu w operacjach kwerend LINQ (C#)
Aby efektywnie pisać zapytania, należy zrozumieć, jak typy zmiennych w pełnej operacji zapytania odnoszą się do siebie nawzajem. Jeśli rozumiesz te relacje, łatwiej zrozumiesz przykłady LINQ i przykłady kodu w dokumentacji. Ponadto dowiesz się, co się dzieje, gdy zmienne są niejawnie wpisywane przy użyciu metody var
.
Operacje zapytań LINQ są silnie typizowane w źródle danych, w samym zapytaniu i w wykonaniu zapytania. Typ zmiennych w zapytaniu musi być zgodny z typem elementów w źródle danych i typem zmiennej iteracji w instrukcji foreach
. To silne wpisywanie gwarantuje, że błędy typu są przechwytywane w czasie kompilacji, gdy można je poprawić przed ich napotkaniem przez użytkowników.
Aby zademonstrować relacje typów, większość przykładów, które są zgodne z jawnym wpisywaniem dla wszystkich zmiennych. W ostatnim przykładzie pokazano, jak te same zasady mają zastosowanie nawet w przypadku używania niejawnego pisania przy użyciu polecenia var
.
Zapytania, które nie przekształcają danych źródłowych
Na poniższej ilustracji przedstawiono operację zapytania LINQ to Objects, która nie wykonuje żadnych przekształceń na danych. Źródło zawiera sekwencję ciągów, a dane wyjściowe zapytania są również sekwencją ciągów.
- Argument typu źródła danych określa typ zmiennej zakresu.
- Typ wybranego obiektu określa typ zmiennej kwerendy. Oto
name
ciąg. W związku z tym zmienna kwerendy toIEnumerable<string>
. - Zmienna kwerendy jest iteracja w instrukcji
foreach
. Ponieważ zmienna kwerendy jest sekwencją ciągów, zmienna iteracji jest również ciągiem.
Zapytania przekształcające dane źródłowe
Na poniższej ilustracji przedstawiono operację zapytania LINQ to SQL, która wykonuje prostą transformację danych. Zapytanie przyjmuje sekwencję Customer
obiektów jako dane wejściowe i wybiera tylko Name
właściwość w wyniku. Ponieważ Name
jest ciągiem, zapytanie tworzy sekwencję ciągów jako dane wyjściowe.
- Argument typu źródła danych określa typ zmiennej zakresu.
- Instrukcja
select
zwracaName
właściwość zamiast kompletnegoCustomer
obiektu. PonieważName
jest ciągiem, argument typu tocustNameQuery
string
, a nieCustomer
. - Ponieważ
custNameQuery
jest sekwencją ciągów,foreach
zmienna iteracji pętli musi być również zmiennąstring
.
Na poniższej ilustracji przedstawiono nieco bardziej złożoną transformację. Instrukcja select
zwraca typ anonimowy, który przechwytuje tylko dwa elementy członkowskie oryginalnego Customer
obiektu.
- Argument typu źródła danych jest zawsze typem zmiennej zakresu w zapytaniu.
select
Ponieważ instrukcja generuje typ anonimowy, zmienna kwerendy musi być niejawnie wpisywana przy użyciu metodyvar
.- Ponieważ typ zmiennej kwerendy jest niejawny, zmienna iteracji w
foreach
pętli musi być również niejawna.
Zezwalanie kompilatorowi na informacje o typie wnioskowania
Chociaż należy zrozumieć relacje typów w operacji zapytania, możesz zezwolić kompilatorowi na wykonywanie wszystkich zadań. Zmienna var słowa kluczowego może być używana dla dowolnej zmiennej lokalnej w operacji zapytania. Poniższa ilustracja jest podobna do przykładowej liczby 2, która została omówiona wcześniej. Jednak kompilator dostarcza silny typ dla każdej zmiennej w operacji zapytania.
LINQ i typy ogólne (C#)
Zapytania LINQ są oparte na typach ogólnych. Nie potrzebujesz dogłębnej wiedzy na temat typów ogólnych przed rozpoczęciem pisania zapytań. Warto jednak zapoznać się z dwoma podstawowymi pojęciami:
- Podczas tworzenia wystąpienia klasy kolekcji ogólnej, takiej jak List<T>, zastąp ciąg "T" typem obiektów, które będą przechowywane na liście. Na przykład lista ciągów jest wyrażona jako
List<string>
, a listaCustomer
obiektów jest wyrażona jakoList<Customer>
. Lista ogólna jest silnie typizowana i zapewnia wiele korzyści w przypadku kolekcji, które przechowują swoje elementy jako Object. Jeśli spróbujesz dodać elementCustomer
doList<string>
elementu , podczas kompilacji wystąpi błąd. Łatwo jest używać kolekcji ogólnych, ponieważ nie trzeba wykonywać rzutowania typu w czasie wykonywania. - IEnumerable<T> to interfejs, który umożliwia wyliczanie klas kolekcji ogólnych przy użyciu instrukcji
foreach
. Klasy kolekcji ogólnych obsługują IEnumerable<T> tak samo, jak klasy kolekcji nieogólne, takie jak ArrayList obsługa IEnumerable.
Aby uzyskać więcej informacji na temat typów ogólnych, zobacz Ogólne.
Zmienne IEnumerable<T> w zapytaniach LINQ
Zmienne zapytania LINQ są wpisywane jako IEnumerable<T> lub typ pochodny, taki jak IQueryable<T>. Gdy zobaczysz zmienną kwerendy, która jest typowana jako IEnumerable<Customer>
, oznacza to tylko, że zapytanie, gdy jest wykonywane, spowoduje utworzenie sekwencji zero lub więcej Customer
obiektów.
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żliwienie kompilatorowi obsługi deklaracji typów ogólnych
Jeśli wolisz, możesz uniknąć składni ogólnej przy użyciu słowa kluczowego var . Słowo var
kluczowe nakazuje kompilatorowi wnioskowanie typu zmiennej zapytania przez przyjrzenie się źródle danych określonemu w klauzuli from
. Poniższy przykład tworzy ten sam skompilowany kod co w poprzednim przykładzie:
var customerQuery2 =
from cust in customers
where cust.City == "London"
select cust;
foreach(var customer in customerQuery2)
{
Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}
Słowo var
kluczowe jest przydatne, gdy typ zmiennej jest oczywisty lub gdy nie jest tak ważne, aby jawnie określić zagnieżdżone typy ogólne, takie jak te, które są generowane przez zapytania grupy. Ogólnie rzecz biorąc, zalecamy, aby jeśli używasz var
metody , należy pamiętać, że może to utrudnić innym osobom odczytywanie kodu. Aby uzyskać więcej informacji, zobacz Niejawnie wpisane zmienne lokalne.