Отношения между типами в операциях запросов LINQ (C#)
Для эффективного написания запросов следует понимать, как типы переменных связаны друг с другом в полной операции запроса. В таком случае вам будет проще работать с примерами 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, рассмотренный выше. Однако компилятор предоставляет строгий тип для каждой переменной в операции запроса.
Дополнительные сведения о var
см. в разделе Неявно типизированные локальные переменные.