LINQ использует модель отложенного выполнения, которая означает, что результирующая последовательность не возвращается во время вызова операторов Linq, но вместо этого эти операторы возвращают объект, который затем возвращает элементы последовательности только при перечислении этого объекта.
var results = someCollection.Select(item => item.Foo).Where(foo => foo < 3);
Когда мы перечисляем объект результатов, он будет перебирать someCollection
только один раз, и для каждого элемента, запрошенного во время итерации, код (расположенный внутри results
объекта) выполняет операцию отображения и, наконец, выполняет фильтрацию.
Но мне трудно понять, что происходит под капотом:
a) Является ли метод Where
тем, который фактически создает results
объект?
b) Если Where
действительно создает results
объект, то я предполагаю, что Where
нужно также извлечь некоторую логику из оператора Select
(например, return Item.Foo
), чтобы он мог поместить эту логику в results
объект?
в) Если мои предположения верны, как Where
может извлечь логику из Select
?
d) В любом случае, объект results
содержит необходимую логику L для оценки каждого элемента в someCollection
. Я предполагаю, что эта логика L не делает никаких дополнительных вызовов операторам Select
и Where
при оценке каждого элемента в someCollection
?
Спасибо
EDIT:
1)
Ваше предположение в г) неверно - результаты просто
IEnumerable, который возвращается расширением Where ()
метод. Только когда вы перебираете перечисление (т.е. используете foreach
или ToList ()) будет создана последовательность «по-настоящему». В таком случае -
Вы даже можете увидеть это, если вы установите точку останова - все Linq
методы расширения выполняются по очереди - метод расширения Where ()
спросит вход IEnumerable для его первого элемента, который приведет к
оператор Select (), в свою очередь, получит первый элемент из
лежащей в основе коллекции и выплюнуть элемент FooType.
a) Итак, Where
и Select
сначала вызываются в операторе присваивания при присваивании результирующего объекта переменной results
(var results=...
). И затем по очереди Where
/ Select
также вызывается (изнутри объекта results
) для каждого элемента при перечислении someCollection
?
b) Предполагая, что results
экземпляр имеет тип C - когда C класс определен / создан? Это определяется методом Where
или класс C определяется компилятором и, таким образом, Where
возвращает только экземпляр C
?
2)
Только когда вы перебираете перечисление (т.е. с помощью foreach или
ToList ()) будет создавать последовательность «по-настоящему». В этот момент вы
можно даже увидеть это, если вы установите точку останова - все расширение Linq
методы выполняются по очереди - метод расширения Where () спросит
входной IEnumerable для его первого элемента, который вызовет
Оператор Select () в свою очередь получит первый элемент из базового
собирать и выплевывать элемент FooType
a) Вы говорите, что из results
объекта Select
и Where
вызываются для каждого элемента I в коллекции. Предполагая, что I не реализует IEnumerable<>
, как тогда можно вызывать Select
и Where
на I
, если они могут работать только на IEnumerable<>
типах?