Эта программа дает следующий результат.
Количество положительных значений в массиве nums: 3
Обратите внимание на то, что цикл foreach
не указан в данной программе явным образом. Вместо этого запрос выполняется автоматически благодаря вызову метода расширения Count()
.
Любопытно, что запрос из приведенной выше программы можно было бы сформировать и следующим образом.
var posNums = from n in nums where n > 0 select n;
int len = posNums.Count(); // запрос выполняется здесь
В данном случае метод Count()
вызывается для переменной запроса. И в этот момент запрос выполняется для получения подсчитанного количества.
К числу других методов расширения, вызывающих немедленное выполнение запроса, относятся методы ТоArray()
и ToList()
. Оба этих метода расширения определены в классе Enumerable
. Метод ToAtray()
возвращает результаты запроса в массиве, а метод ToList()
— результаты запроса в форме коллекции List
. (Подробнее о коллекциях речь пойдет в главе 25.) В обоих случаях для получения результатов выполняется запрос. Например, в следующем фрагменте кода сначала получается массив результатов, сформированных по приведенному выше запросу в переменной posNums
, а затем эти результаты выводятся на экран.
int[] pnums = posNum.ToArray(); // запрос выполняется здесь
foreach(int i in pnums)
Console.Write(i + " ");
}
Деревья выражений
Еще одним средством, связанным с LINQ, является System.Linq.Expressions.Expression
. Они оказываются пригодными в тех случаях, когда запрос выполняется вне программы, например средствами SQL в базе данных. Если запрос представлен в виде данных, то его можно преобразовать в формат, понятный для базы данных. Этот процесс выполняется, например, средствами LINQ to SQL в интегрированной среде разработки Visual Studio. Таким образом, деревья выражений способствуют поддержке в C# различных баз данных.
Для получения исполняемой формы дерева выражений достаточно вызвать метод Compile()
, определенный в классе Expression
. Этот метод возвращает ссылку, которая может быть присвоена делегату для последующего выполнения. А тип делегата может быть объявлен собственным или же одним из предопределенных типов делегата Func
в пространстве имен System
. Две формы делегата Func
уже упоминались ранее при рассмотрении методов запроса, но существует и другие его формы.
Деревьям выражений присуще следующее существенное ограничение: они могут представлять только одиночные лямбда-выражения. С их помощью нельзя представить блочные лямбда-выражения.
Ниже приведен пример программы, демонстрирующий конкретное применение дерева выражений. В этой программе сначала создается дерево выражений, данные которого представляют метод, определяющий, является ли одно целое число множителем другого. Затем это дерево выражений компилируется в исполняемый код. И наконец, в этой программе демонстрируется выполнение скомпилированного кода.
// Пример простого дерева выражений.
using System;
using System.Linq;
using System.Linq.Expressions;
class SimpleExpTree {
static void Main() {
// Представить лямбда-выражение в виде данных.
Expression
IsFactorExp = (n, d) => (d != 0) ? (n % d) == 0 : false;
// Скомпилировать данные выражения в исполняемый код.
Func
IsFactor = IsFactorExp.Compile();
// Выполнить выражение,
if(IsFactor(10, 5))
Console.WriteLine("Число 5 является множителем 10.");
if(!IsFactor(10, 7))
Console.WriteLine("Число 7 не является множителем 10.");
Console.WriteLine();
}
}
Вот к какому результату приводит выполнение этой программы.
Число 5 является множителем 10.
Число 7 не является множителем 10.
Данный пример программы наглядно показывает два основных этапа применения дерева выражений. Сначала в ней создается дерево выражений с помощью следующего оператора.
Expression