К категории <���Речной транспорт> относится:
лодка
каноэ
Главной частью данной программы, безусловно, является следующий запрос.
var byHow = from how in travelTypes
join trans in transports
on how equals trans.How
into 1st
select new { How = how, Tlist = 1st };
Этот запрос формируется следующим образом. В операторе fromиспользуется переменная диапазона howдля охвата всего массива travelTypes. Напомним, что массив travelTypesсодержит названия общих категорий транспорта: воздушного, наземного, морского и речного. Каждый вид транспорта объединяется в операторе joinсо своей категорией. Например, велосипед, автомашина и поезд объединяются с наземным транспортом. Но благодаря оператору intoдля каждой категории транспорта в операторе joinсоставляется список видов транспорта, относящихся к данной категории. Этот список сохраняется в переменной lst. И наконец, оператор selectвозвращает объект анонимного типа, инкапсулирующий каждое значение переменной how(категории транспорта) вместе со списком видов транспорта. Именно поэтому для вывода результатов запроса требуются два цикла foreach.
foreach(var t in byHow) {
Console.WriteLine("К категории <{0} транспорт> относится:", t.How);
foreach(var m in t.Tlist)
Console.WriteLine(" " + m.Name);
Console.WriteLine();
}
Во внешнем цикле получается объект, содержащий наименование общей категории транспорта, и список видов транспорта, относящихся к этой категории. А во внутреннем цикле выводятся отдельные виды транспорта.
Синтаксис запроса, описанный в предыдущих разделах, применяется при формировании большинства запросов в С#. Он удобен, эффективен и компактен, хотя и не является единственным способом формирования запросов. Другой способ состоит в использовании методов запроса , которые могут вызываться для любого перечислимого объекта, например массива.
Основные методы запроса
Методы запроса определяются в классе System.Linq.Enumerableи реализуются в виде методов расширения функций обобщенной формы интерфейса IEnumerable. (Методы запроса определяются также в классе System.Linq.Queryable, расширяющем функции обобщенной формы интерфейса IQueryable, но этот интерфейс в настоящей главе не рассматривается.) Метод расширения дополняет функции другого класса, но без наследования. Поддержка методов расширения была внедрена в версию C# 3.0 и более подробно рассматривается далее в этой главе. А до тех пор достаточно сказать, что методы запроса могут вызываться только для тех объектов, которые реализуют интерфейс IEnumerable.
В классе Enumerableпредоставляется немало методов запроса, но основными считаются те методы, которые соответствуют описанным ранее операторам запроса. Эти методы перечислены ниже вместе с соответствующими операторами запроса. Следует, однако, иметь в виду, что эти методы имеют также перегружаемые формы, а здесь они представлены лишь в самой простой своей форме. Но именно эта их форма используется чаще всего.
Оператор запроса Эквивалентный метод запроса
select Select( selector)
where Where( predicate)
orderby OrderBy( keySelector) или
OrderByDescending( keySelector)
join Join (inner, outerKeySelector,
innerKeySelector, resultSelector)
group GroupBy( keySelector)
За исключением метода Join(), остальные методы запроса принимают единственный аргумент, который представляет собой объект некоторой разновидности обобщенного типа Func. Это тип встроенного делегата, объявляемый следующим образом:
delegate TResult Func(Т arg)
где TResultобозначает тип результата, который дает делегат, а Т — тип элемента. В методах запроса аргументы selector , predicate или keySelector определяют действие, которое предпринимает метод запроса. Например, в методе Where()аргумент predicate определяет порядок отбора данных в запросе. Каждый метод запроса возвращает перечислимый объект. Поэтому результат выполнения одного метода запроса можно использовать для вызова другого, соединяя эти методы в цепочку.
Метод Join()принимает четыре аргумента. Первый аргумент ( inner ) представляет собой ссылку на вторую объединяемую последовательность, а первой является последовательность, для которой вызывается метод Join(). Селектор ключа для первой последовательности передается в качестве аргумента outerKeySelector , а селектор ключа для второй последовательности — в качестве аргумента innerKeySelector . Результат объединения обозначается как аргумент resultSelector . Аргумент outerKeySelector имеет тип Func, аргумент innerKeySelector — тип Func, тогда как аргумент resultSelector — тип Func, где TOuter— тип элемента из вызывающей последовательности; Tinner— тип элемента из передаваемой последовательности; TResult— тип элемента из объединяемой в итоге последовательности, возвращаемой в виде перечислимого объекта.
Читать дальше