Имеет смысл спросить о конкретном аспекте LINQ. Это немного похоже на вопрос «Как работает Windows» в противном случае.
Ключевые части LINQ для меня, с точки зрения C #:
- Выражение деревьев. Это представления кода в виде данных. Например, дерево выражений может представлять понятие «взять строковый параметр, вызвать для него свойство Length и вернуть результат». Тот факт, что они существуют как data , а не как скомпилированный код, означает, что поставщики 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
Они переводятся компилятором C # в "нормальный" C # 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" страница сайта C # in Depth.
Обычно провайдеры, такие как LINQ to SQL, работают через класс Queryable
. По своей сути они переводят деревья выражений в другие форматы запросов, а затем создают соответствующие объекты с результатами выполнения этих внепроцессных запросов.
Это охватывает все, что вас интересовало? Если есть что-то конкретное, о чем вы все еще хотите знать, просто отредактируйте свой вопрос, и я пойду.