Ответ 1
Спрашивается о конкретном аспекте LINQ. Это немного похоже на запрос "Как работает Windows" в противном случае.
Ключевые части LINQ для меня, с точки зрения С#:
- Деревья выражений. Это представление кода как данных. Например, дерево выражений может представлять собой понятие "взять строковый параметр, вызвать свойство Length на нем и вернуть результат". Тот факт, что они существуют как данные, а не как скомпилированный код, означает, что поставщики LINQ, такие как LINQ to SQL, могут анализировать их и преобразовывать в SQL.
-
Лямбда-выражения. Вот такие выражения:
x => x * 2 (int x, int y) => x * y () => { Console.WriteLine("Block"); Console.WriteLine("Lambda"); }
Лямбда-выражения преобразуются либо в делегаты, либо в деревья выражений.
-
Анонимные типы. Вот такие выражения:
new { X=10, Y=20 }
Они все еще статически типизированы, просто компилятор генерирует неизменяемый тип для вас со свойствами
X
иY
. Они обычно используются сvar
, который позволяет выводить тип локальной переменной из его выражения инициализации. -
Выражения запроса. Вот такие выражения:
from person in people where person.Age < 18 select person.Name
Они транслируются компилятором С# в "обычный" С# 3.0 (т.е. форма, которая не использует выражения запроса). После этого применяется разрешение перегрузки и т.д., Что является абсолютно ключом к возможности использования одного синтаксиса запроса с несколькими типами данных, без компилятора, имеющего какие-либо знания типов, таких как Queryable. Вышеприведенное выражение будет переведено на:
people.Where(person => person.Age < 18) .Select(person => person.Name)
-
Методы расширения. Это статические методы, которые можно использовать так, как если бы они были методами экземпляра первого параметра. Например, метод расширения, подобный этому:
public static int CountAsciiDigits(this string text) { return text.Count(letter => letter >= '0' && letter <= '9'); }
можно использовать следующим образом:
string foo = "123abc456"; int count = foo.CountAsciiDigits();
Обратите внимание, что в реализации
CountAsciiDigits
используется другой метод расширения,Enumerable.Count()
.
Это большинство соответствующих языковых аспектов. Тогда есть реализации стандартных операторов запросов, в LINQ-провайдерах, таких как LINQ to Objects и LINQ to SQL и т.д. У меня есть презентация о том, насколько разумно просто реализовать LINQ to Objects - это на "Talks" на веб-сайте С# в глубину.
Способ работы провайдеров, таких как LINQ to SQL, обычно осуществляется через класс Queryable
. По своей сути они преобразуют деревья выражений в другие форматы запросов, а затем создают соответствующие объекты с результатами выполнения этих внепроцессных запросов.
Это покрывает все, что вас интересует? Если есть что-то, о чем вы все еще хотите узнать, просто отредактируйте свой вопрос, и я поеду.