Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Чтобы эффективно писать запросы, следует понять, как типы переменных в полной операции запроса связаны друг с другом. Если вы понимаете эти связи, вы сможете более легко понять примеры LINQ и примеры кода в документации. Кроме того, вы поймете, что происходит при неявном типизировании переменных с помощью var
.
Операции запроса LINQ строго типизированы в источнике данных, в самом запросе и в выполнении запроса. Тип переменных в запросе должен быть совместим с типом элементов в источнике данных и типом переменной итерации в инструкции foreach
. Эта строгая типизация гарантирует, что ошибки типов обнаруживаются во время компиляции, когда они могут быть исправлены перед тем, как пользователи столкнутся с ними.
Для демонстрации этих связей типов большинство последующих примеров используют явное указание типов для всех переменных. В последнем примере показано, как применяются те же принципы даже при использовании неявного ввода с помощью var
.
Запросы, не преобразующие исходные данные
На следующем рисунке показана операция запроса LINQ to Objects, которая не выполняет преобразований данных. Источник содержит последовательность строк, а выходные данные запроса — это также последовательность строк.
- Аргумент типа источника данных определяет тип переменной диапазона.
- Тип выбранного объекта определяет тип переменной запроса.
name
— это строка. Таким образом, переменная запроса является переменнойIEnumerable<string>
. - Переменная запроса переитерируется в инструкции
foreach
. Так как переменная запроса представляет собой последовательность строк, переменная итерации также является строкой.
Запросы, которые преобразуют исходные данные
На следующем рисунке показана операция запроса LINQ to SQL, которая выполняет простое преобразование данных. Запрос принимает на вход последовательность объектов Customer
и выбирает только свойство Name
в результате. Так как Name
это строка, запрос создает последовательность строк в виде выходных данных.
- Аргумент типа источника данных определяет тип переменной диапазона.
- Инструкция
select
возвращаетName
свойство вместо полногоCustomer
объекта. Так какName
это строка, аргументcustNameQuery
типа имеетstring
значение , а неCustomer
. - Так как
custNameQuery
— это последовательность строк, переменная циклаforeach
также должна быть строкойstring
.
На следующем рисунке показано немного более сложное преобразование. Оператор select
возвращает анонимный тип, который содержит только два элемента из исходного объекта Customer
.
- Аргумент типа источника данных всегда является типом переменной диапазона в запросе.
-
select
Так как инструкция создает анонимный тип, переменная запроса должна быть неявно типирована с помощьюvar
. - Поскольку тип переменной запроса неявен, переменная итерации в цикле
foreach
также должна быть неявной.
Позволяя компилятору определить информацию о типе
Хотя вы должны понимать связи типов в операции запроса, вы можете позволить компилятору выполнять всю работу. Ключевое слово var можно использовать для любой локальной переменной в операции запроса. Следующий рисунок похож на пример номер 2, который обсуждался ранее. Однако компилятор предоставляет надежный тип для каждой переменной в операции запроса.
LINQ и универсальные типы (C#)
Запросы LINQ основаны на универсальных типах. Вам не требуется глубокое знание универсальных шаблонов, прежде чем начать писать запросы. Однако вам может потребоваться понять два основных понятия:
- При создании экземпляра универсального класса коллекции, например List<T>, замените "T" типом объектов, которые будет храниться в списке. Например, список строк выражается как
List<string>
, а списокCustomer
объектов выражается какList<Customer>
. Универсальный список строго типизирован и предоставляет множество преимуществ по сравнению с коллекциями, которые хранят их элементы как Object. Если вы попытаетесь добавитьCustomer
кList<string>
, на этапе компиляции возникнет ошибка. Универсальные коллекции легко использовать, так как вам не нужно выполнять приведение типов во время выполнения. -
IEnumerable<T> — интерфейс, позволяющий перечислить универсальные классы коллекции с помощью инструкции
foreach
. Универсальные классы коллекций поддерживают IEnumerable<T>, также как неуниверсальные классы коллекций, например, ArrayList, поддерживают IEnumerable.
Дополнительные сведения о универсальных типах см. в разделе Generics.
Переменные IEnumerable<T> в запросах LINQ
Переменные запроса LINQ типируются как IEnumerable<T> или производный тип, например IQueryable<T>. При отображении переменной запроса, типизированной как IEnumerable<Customer>
, это просто означает, что запрос, когда он выполняется, будет производить последовательность из нуля или более Customer
объектов.
IEnumerable<Customer> customerQuery = from cust in customers
where cust.City == "London"
select cust;
foreach (Customer customer in customerQuery)
{
Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}
Поручение компилятору обработки деклараций универсальных типов.
Если вы предпочитаете, можно избежать универсального синтаксиса с помощью ключевого слова var . Ключевое var
слово указывает компилятору определить тип переменной запроса, глядя на источник данных, указанный в предложении from
. В следующем примере создается тот же скомпилированный код, что и предыдущий пример:
var customerQuery2 = from cust in customers
where cust.City == "London"
select cust;
foreach(var customer in customerQuery2)
{
Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}
Ключевое var
слово полезно, если тип переменной очевиден или если не так важно явно указывать вложенные универсальные типы, такие как те, которые создаются запросами группы. Как правило, рекомендуется, если вы используете var
, понимать, что это может сделать код более сложным для других пользователей для чтения. Дополнительные сведения см. в разделе Неявно типизированные локальные переменные.