Ответ на (a) короткий, но я более подробно расскажу ниже:
На самом деле компилятор не выполняет связывание - это происходит во время выполнения, черезнормальная организация объектов!Здесь гораздо меньше волшебства, чем может показаться на первый взгляд - Джон Скит недавно выполнил шаг «Где предложение» в своей серии блогов «Реализация LINQ to Objects».Я бы порекомендовал прочитать это.
В очень короткие сроки происходит следующее: каждый раз, когда вы вызываете метод расширения Where
, он возвращает новый объект WhereEnumerable
, который имеет две вещи - ссылкуна предыдущую IEnumerable
(ту, которую вы назвали Where
) и лямбду, которую вы указали.
Когда вы начнете перебирать эту WhereEnumerable
(например, в foreach
позже вваш код), внутри он просто начинает перебирать IEnumerable
, на который ссылается .
"Этот foreach
только что попросил у меня следующий элемент в моей последовательности, поэтому я оборачиваюсь и спрашиваю вас о следующем элементе в вашей последовательности".
Это продолжается до тех пор, пока мы не достигнем начала координат, которое на самом деле является неким массивом или хранилищем реальных элементов.Когда каждый Enumerable затем говорит «ОК, вот мой элемент», передавая его обратно по цепочке, он также применяет свою собственную пользовательскую логику.Для Where
применяется лямбда-выражение, чтобы проверить, соответствует ли элемент критериям.Если это так, он позволяет перейти к следующему абоненту.Если произойдет сбой, он остановится в этой точке, вернется к своему перечисленному Enumerable и запросит следующий элемент.
Это продолжается до тех пор, пока MoveNext
каждого не вернет false, что означает, что перечисление завершено ибольше нет элементов.
Чтобы ответить (b) , есть всегда разница, но здесь это слишком тривиально, чтобы беспокоиться.Не беспокойся об этом:)