Первый метод, QueryStringsWithOperators(), предлагает наиболее прямолинейный способ создания выражений запросов и идентичен коду примера LinqOverArray, который приводился ранее в главе:
using System.Linq;
static void QueryStringWithOperators()
{
Console.WriteLine("***** Using Query Operators *****");
string[] currentVideoGames = {"Morrowind", "Uncharted 2",
"Fallout 3", "Daxter", "System Shock 2"};
var subset = from game in currentVideoGames
where game.Contains(" ") orderby game select game;
foreach (string s in subset)
{
Console.WriteLine("Item: {0}", s);
}
}
Очевидное преимущество использования операций запросов C# при построении выражений запросов заключается в том, что делегаты Funс<> и вызовы методов Enumerable остаются вне поля зрения и внимания, т.к. выполнение необходимой трансляции возлагается на компилятор С#. Бесспорно, создание выражений LINQ с применением различных операций запросов (from, in, where или orderby) является наиболее распространенным и простым подходом.
Построение выражений запросов с использованием типа Enumerable и лямбда-выражений
Имейте в виду, что применяемые здесь операции запросов LINQ представляют собой сокращенные версии вызова расширяющих методов, определенных в типе Enumerable. Рассмотрим показанный ниже метод QueryStringsWithEnumerableAndLambdas(), который обрабатывает локальный массив строк, но на этот раз в нем напрямую используются расширяющие методы Enumerable:
static void QueryStringsWithEnumerableAndLambdas()
{
Console.WriteLine("***** Using Enumerable / Lambda Expressions *****");
string[] currentVideoGames = {"Morrowind", "Uncharted 2",
"Fallout 3", "Daxter", "System Shock 2"};
// Построить выражение запроса с использованием расширяющих методов,
// предоставленных типу Array через тип Enumerable.
var subset = currentVideoGames
.Where(game => game.Contains(" "))
.OrderBy(game => game).Select(game => game);
// Вывести результаты.
foreach (var game in subset)
{
Console.WriteLine("Item: {0}", game);
}
Console.WriteLine();
}
Здесь сначала вызывается расширяющий метод Where() на строковом массиве currentVideoGames. Вспомните, что класс Array получает данный метод от класса Enumerable. Метод Enumerable.Where() требует параметра типа делегата System.Func. Первый параметр типа упомянутого делегата представляет совместимые с интерфейсом IEnumerable данные для обработки (массив строк в рассматриваемом случае), а второй — результирующие данные метода, которые получаются от единственного оператора, вставленного в лямбда-выражение.
Возвращаемое значение метода Where() в приведенном примере кода скрыто от глаз, но "за кулисами" работа происходит с типом OrderedEnumerable. На объекте указанного типа вызывается обобщенный метод OrderBy(), который также принимает параметр типа делегата Func<>. Теперь производится передача всех элементов по очереди посредством подходящего лямбда-выражения. Результатом вызова OrderBy() является новая упорядоченная последовательность первоначальных данных.
И, наконец, осуществляется вызов метода Select() на последовательности, возвращенной OrderBy(), который в итоге дает финальный набор данных, сохраняемый в неявно типизированной переменной по имени subset.
Конечно, такой "длинный" запрос LINQ несколько сложнее для восприятия, чем предыдущий пример с операциями запросов LINQ. Без сомнения, часть сложности связана с объединением в цепочку вызовов посредством операции точки. Вот тот же самый запрос с выделением каждого шага в отдельный фрагмент (разбивать запрос на части можно разными способами):
static void QueryStringsWithEnumerableAndLambdas2()
{
Console.WriteLine("***** Using Enumerable / Lambda Expressions *****");