C# 4.0 полное руководство - 2011 - Герберт Шилдт
Шрифт:
Интервал:
Закладка:
public string Name { get; set; } public int ItemNumber { get; set; }
public Item(string nv int inum) {
Name = n;
ItemNumber = inum;
}
}
// Класс, связывающий наименование товара с состоянием его запасов на складе, class InStockStatus {
public int ItemNumber { get; set; } public bool InStock { get; set; }
public InStockStatus(int n, bool b) {
ItemNumber = n;
InStock = b;
}
}
class AnonTypeDemo { static void Main() {
Item[] items = {
new Item("Кусачки", 1424), new Item("Тиски", 7892), new Item("Молоток", 8534), new Item("nnna", 6411)
};
InStockStatus[] statusList = {
new InStockStatus(1424, true), new InStockStatus(7892, false), new InStockStatus(8534, true), new InStockStatus (6411, true)
};
// Сформировать запрос, объединяющий объекты классов Item и // InStockStatus для составления списка наименований товаров и их // наличия на складе. Теперь для этой цели используется анонимный тип. var inStockList = from item in items
join entry in statusList
on item.ItemNumber equals entry.ItemNumber select new { Name = item.Name,
InStock = entry.InStock };
Console .WriteLine ("ТоварМаличиеп") ;
// Выполнить запрос и вывести его результаты, foreach(var t in inStockList)
Console.WriteLine("{0}t{1}", t.Name, t.InStock);
}
}
Обратите особое внимание на следующий оператор select.
select new { Name = item.Name,
InStock = entry.InStock };
Он возвращает объект анонимного типа с двумя доступными только для чтения свойствами: Name и InStock. Этим свойствам присваиваются наименование товара и состояние его наличия на складе. Благодаря применению анонимного типа необходимость в упоминавшемся выше классе Temp отпадает.
Обратите также внимание на цикл foreach, в котором выполняется запрос. Теперь переменная шага этого цикла объявляется с помощью ключевого слова var. Это необходимо потому, что у типа объекта, хранящегося в переменной inStockList, нет имени. Данная ситуация послужила одной из причин, по которым в C# были внедрены неявно типизированные переменные, поскольку они нужны для поддержки анонимных типов.
Прежде чем продолжить изложение, следует отметить еще один заслуживающий внимания аспект анонимных типов. В некоторых случаях, включая и рассмотренный выше, синтаксис анонимного типа упрощается благодаря применению инициализатора проекции. В данном случае просто указывается имя самого инициализатора. Это имя автоматически становится именем свойства. В качестве примера ниже приведен другой вариант оператора select из предыдущей программы.
select new { item.Name, entry.InStock };
В данном примере имена свойств остаются такими же, как и прежде, а компилятор автоматически "проецирует" идентификаторы Name и InStock, превращая их в свойства анонимного типа. Этим свойствам присваиваются прежние значения, обозначаемые item.Name и entry. InStock соответственно.
Создание группового объединения
Как пояснялось ранее, оператор into можно использовать вместе с оператором join для создания группового объединения, образующего последовательность, в которой каждый результат состоит из элементов данных из первой последовательности и группы всех совпадающих элементов из второй последовательности. Примеры группового объединения не приводились выше потому, что в этом объединении нередко применяется анонимный тип. Но теперь, когда представлены анонимные типы, можно обратиться к простому примеру группового объединения.
В приведенном ниже примере программы групповое объединение используется для составления списка, в котором различные транспортные средства (автомашины, суда и самолеты) организованы по общим для них категориям транспорта: наземного, морского, воздушного и речного. В этой программе сначала создается класс Transport, связывающий вид транспорта с его классификацией. Затем в методе Main () формируются две входные последовательности. Первая из них представляет собой массив символьных строк, содержащих названия общих категорий транспорта: наземного, морского, воздушного и речного, а вторая — массив объектов типа Transport, инкапсулирующих различные транспортные средства. Полученное в итоге групповое объединение используется для составления списка транспортных средств, организованных по соответствующим категориям.
// Продемонстрировать применение простого группового объединения.
using System; using System.Linq;
*
// Этот класс связывает наименование вида транспорта,
// например поезда, с общей классификацией транспорта:
// наземного, морского, воздушного или речного, class Transport {
public string Name { get; set; } public string How { get; set; }
public Transport(string n, string h) {
Name = n;
How = h;
}
}
class GroupJoinDemo { static void Main() {
// Массив классификации видов транспорта, string[] travelTypes = {
"Воздушный",
"Морской",
"Наземный",
"Речной",
};
// Массив видов транспорта.
Transport[] transports = { 1
new Transport("велосипед", "Наземный"), new Transport ("аэростат", "Воздушный"), new Transport("лодка", "Речной"), new Transport("самолет", "Воздушный"), new Transport("каноэ", "Речной"), new Transport("биплан", "Воздушный"), new Transport("автомашина", "Наземный"), new Transport("судно", "Морской"), new Transport("поезд", "Наземный")
};
// Сформировать запрос, в котором групповое // объединение используется для составления списка
// видов транспорта по соответствующим категориям, var byHow = from how in travelTypes
join trans in transports on how equals trans.How into 1st
select new { How = how, Tlist = 1st };
// Выполнить запрос и вывести его результаты, foreach(var t in byHow) {
Console.WriteLine("К категории <{0} транспорт> относится:", t.How);
foreach(var m in t.Tlist)
Console.WriteLine(" " + m.Name);
Console.WriteLine();
}
}
}
Ниже приведен результат выполнения этой программы.
К категории <Воздушный транспорт> относится: аэростат самолет биплан
К категории <Морской транспорт> относится: судно
К категории <Наземный транспорт> относится: велосипед автомашина поезд
К категории <Речной транспорт> относится: лодка каноэ
Главной частью данной программы, безусловно, является следующий запрос.
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 составляется список видов транспорта, относящихся к данной категории. Этот список сохраняется в переменной 1st. И наконец, оператор 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<T>. (Методы запроса определяются также в классе System. Linq. Queryable, расширяющем функции обобщенной формы интерфейса IQueryable<T>, но этот интерфейс в настоящей главе не рассматривается.) Метод расширения дополняет функции другого класса, но без наследования. Поддержка методов расширения была внедрена в версию C# 3.0 и более подробно рассматривается далее в этой главе. А до тех пор достаточно сказать, что методы запроса могут вызываться только для тех объектов, которые реализуют интерфейс IEnumerable<T>.