LINQ - это широкий набор технологий, основанных (например) на синтаксисе понимания запросов, например:
var qry = from x in source.Foo
where x.SomeProp == "abc"
select x.Bar;
который отображается компилятором в код:
var qry = source.Foo.Where(x => x.SomeProp == "abc").Select(x => x.Bar);
и тут начинается настоящее волшебство. Обратите внимание, что мы не сказали, что Fooздесь находится - и компилятору все равно! Пока он может разрешить некоторый подходящий метод, называемый, Whereкоторый может принимать лямбду, и в результате этого есть некоторый Select метод, который может принимать лямбда, он счастлив.
Теперь представьте, что лямбда -выражение может быть скомпилировано либо в анонимный метод (делегат для LINQ-to-Objects, который включает LINQ-to-DataSet), либо в дерево выражений (модель времени выполнения, представляющая лямбда-выражение в объектной модели. ).
Для данных в памяти (обычно IEnumerable<T>) он просто выполняет делегат - быстро и быстро. Но для IQueryable<T>объектного представления выражения (а LambdaExpression<...>) он может разделить его и применить к любому примеру «LINQ-to-Something».
Для баз данных (LINQ-to-SQL, LINQ-to-Entities) это может означать написание TSQL, например:
SELECT x.Bar
FROM [SomeTable] x
WHERE x.SomeProp = @p1
Но это может (например, для служб данных ADO.NET) означать написание HTTP-запроса.
Выполнение хорошо написанного запроса TSQL, который возвращает небольшой объем данных, происходит быстрее, чем загрузка всей базы данных по сети с последующей фильтрацией на клиенте. Однако у обоих есть идеальные сценарии и совершенно неверные сценарии.
Цель и преимущество здесь - позволить вам использовать единый синтаксис с проверкой статической точностью для запроса широкого диапазона источников данных и сделать код более выразительным (например, "традиционный" код для группировки данных не очень ясно с точки зрения того, что он пытается сделать - он теряется в массе кода).