Чтение онлайн

на главную

Жанры

Полное руководство. С# 4.0
Шрифт:

Оператор let может также использоваться для хранения неперечислимого значе ния. В качестве примера ниже приведен более эффективный вариант формирования запроса в программе IntoDemo из предыдущего раздела. var webAddrs = from addr in websites let idx = addr.LastIndexOf('.') where idx != -1 group addr by addr.Substring(idx) into ws where ws.Count > 2 select ws;

В этом варианте индекс последнего вхождения символа точки в строку присваи вается переменной idx. Данное значение затем используется в методе Substring. Благодаря этому исключается необходимость дважды искать символ точки в строке. Объединение двух последовательностей с помощью оператора join

Когда приходится иметь дело с базами данных, то зачастую требуется формиро вать последовательность, увязывающую данные из разных источников. Например, в Интернет-магазине может быть организована одна база данных, связывающая наи менование

товара с его порядковым номером, и другая база данных, связывающая по рядковый номер товара с состоянием его запасов на складе. В подобной ситуации мо жет возникнуть потребность составить список, в котором состояние запасов товаров на складе отображается по их наименованию, а не порядковому номеру. Для этой цели придется каким-то образом "увязать" данные из двух разных источников (баз данных). И это нетрудно сделать с помощью такого средства LINQ, как оператор join.

Ниже приведена общая форма оператора join (совместно с оператором from). from переменная_диапазона_А in источник_данных_А join переменная_диапазона_В in источник_данных_В

on переменнаядиапазонаА. свойство equals переменнаядиапазонаВ. свойство Применяя оператор join, следует иметь в виду, что каждый источник должен со держать общие данные, которые можно сравнивать. Поэтому в приведенной выше форме этого оператора источникданныхА и источникданныхВ должны иметь нечто общее, что подлежит сравнению. Сравниваемые элементы данных указываются в части on данного оператора. Поэтому если переменнаядиапазонаА.свойство и переменнаядиапазонаА.свойство равны, то эти элементы данных "увязыва ются" успешно. По существу, оператор join выполняет роль своеобразного фильтра, отбирая только те элементы данных, которые имеют общее значение.

Как правило, оператор join возвращает последовательность, состоящую из дан ных, полученных из двух источников. Следовательно, с помощью оператора join мож но сформировать новый список, состоящий из элементов, полученных из двух разных источников данных. Это дает возможность организовать данные по-новому.

Ниже приведена программа, в которой создается класс Item, инкапсулирующий наименование товара и его порядковый номер. Затем в этой программе создается еще один класс InStockStatus, связывающий порядковый номер товара с булевым свойством, которое указывает на наличие или отсутствие товара на складе. И нако нец, в данной программе создается класс Temp с двумя полями: строковым (string) и булевым (bool). В объектах этого класса будут храниться результаты запроса. В этом запросе оператор join используется для получения списка, в котором наименование товара связывается с состоянием его запасов на складе. // Продемонстрировать применение оператора join. using System; using System.Linq; // Класс, связывающий наименование товара с его порядковым номером. class Item { public string Name { get; set; } public int ItemNumber { get; set; } public Item(string n, 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 Temp { public string Name { get; set; } public bool InStock { get; set; } public Temp(string n, bool b) { Name = n; InStock = b; } } class JoinDemo { static void Main { Item[] items = { new Item("Кусачки", 1424), new Item("Тиски", 7892), new Item("Молоток", 8534), new Item("Пила", 6411) }; InStockStatus[] statusList = { new InStockStatus(1424, true), new InStockStatus(7892, false), new InStockStatus(8534, true), new InStockStatus(6411, true) }; // Сформировать запрос, объединяющий объекты классов Item // и InStockStatus для составления списка наименований товаров // и их наличия на складе. Обратите внимание на формирование // последовательности объектов класса Temp. var inStockList = from item in items join entry in statusList on item.ItemNumber equals entry.ItemNumber select new Temp(item.Name, entry.InStock); Console.WriteLine("Товар\tНаличие\n"); // Выполнить запрос и вывести его результаты. foreach(Temp t in inStockList) Console.WriteLine("{0}\t{1}t.Name, t.InStock); } }

Эта программа дает следующий результат. Товар Наличие Кусачки True Тиски False Молоток True Пила True

Для того чтобы стал понятнее принцип действия оператора join, рассмотрим каж дую строку запроса из приведенной выше программы по порядку. Этот запрос начи нается, как обычно, со следующего оператора from. var inStockList = from item in items

В этом операторе указывается переменная диапазона item для источника данных items, который представляет собой массив объектов класса Item. В классе Item ин капсулируются наименование товара и порядковый номер товара, хранящегося на складе.

Далее следует приведенный ниже оператор join. join entry in statusList on item.ItemNumber equals entry.ItemNumber

В этом операторе указывается переменная диапазона entry для источника данных statusList, который представляет собой массив объектов класса InStockStatus, связывающего порядковый номер товара с состоянием его запасов на складе. Следо вательно, у массивов items и statusList имеется общее свойство: порядковый но мер товара. Именно это свойство используется в части on/equals оператора join для описания связи, по которой из двух разных источников данных выбираются наимено вания товаров, когда их порядковые номера совпадают.

И наконец, оператор select возвращает объект класса Temp, содержащий наиме нование товара и состояние его запасов на складе. select new Temp(item.Name, entry.InStock);

Таким образом, последовательность результатов, получаемая по данному запросу, состоит из объектов типа Temp.

Рассмотренный здесь пример применения оператора join довольно прост. Тем не менее этот оператор поддерживает и более сложные операции с источниками дан ных. Например, используя совместно операторы into и join, можно создать групповое объединение, чтобы получить результат, состоящий из первой последовательности и группы всех совпадающих элементов из второй последовательности. (Соответствую щий пример будет приведен далее в этой главе.) Как правило, время и усилия, затра ченные на полное освоение оператора join, окупаются сторицей, поскольку он дает возможность распознавать данные во время выполнения программы. Это очень ценная возможность. Но она становится еще ценнее, если используются анонимные типы, о которых речь пойдет в следующем разделе. Анонимные типы

В C# предоставляется средство, называемое анонимным типом и связанное непо средственно с LINQ. Как подразумевает само название, анонимный тип представляет собой класс, не имеющий имени. Его основное назначение состоит в создании объек та, возвращаемого оператором select. Результатом запроса нередко оказывается по следовательность объектов, которые составляются из членов, полученных из двух или более источников данных (как, например, в операторе join), или же включают в себя подмножество членов из одного источника данных. Но в любом случае тип возвращае мого объекта зачастую требуется только в самом запросе и не используется в остальной части программы. Благодаря анонимному типу в подобных случаях отпадает необхо димость объявлять класс, который предназначается только для хранения результата запроса.

Анонимный тип объявляется с помощью следующей общей формы: new { имя_А = значение_А, имя_В = значение_В, ... }

где имена обозначают идентификаторы, которые преобразуются в свойства, доступ ные только для чтения и инициализируемые значениями, как в приведенном ниже примере. new { Count = 10, Max = 100, Min = 0 }

В данном примере создается класс с тремя открытыми только для чтения свойства ми: Count, Мах и Min, которым присваиваются значения 10, 100 и 0 соответственно. К этим свойствам можно обращаться по имени из другого кода. Следует заметить, что в анонимном типе используются инициализаторы объектов для установки их полей и свойств в исходное состояние. Как пояснялось в главе 8, инициализаторы объектов обеспечивают инициализацию объекта без явного вызова конструктора. Именно это и требуется для анонимных типов, поскольку явный вызов конструктора для них невоз можен. (Напомним, что у конструкторов такое же имя, как и у их класса. Но у аноним ного класса нет имени, а значит, и нет возможности вызвать его конструктор.) Итак, у анонимного типа нет имени, и поэтому для обращения к нему приходится использовать неявно типизированную переменную. Это дает компилятору возмож ность вывести надлежащий тип. В приведенном ниже примере объявляется перемен ная myOb, которой присваивается ссылка на объект, создаваемый в выражении аноним ного типа. var myOb = new { Count = 10, Max = 100, Min = 0 }

Это означает, что следующие операторы считаются вполне допустимыми. Console.WriteLine("Счет равен " + myOb.Count); if(i <= myOb.Max && i >= myOb.Min) // ...

Напомним, что при создании объекта анонимного типа указываемые идентифи каторы становятся свойствами, открытыми только для чтения. Поэтому их можно ис пользовать в других частях кода.

Термин анонимный тип не совсем оправдывает свое название. Ведь тип оказывается анонимным только для программирующего, но не для компилятора, который присва ивает ему внутреннее имя. Следовательно, анонимные типы не нарушают принятые в C# правила строгого контроля типов.

Поделиться:
Популярные книги

Мастер 6

Чащин Валерий
6. Мастер
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер 6

Жребий некроманта. Надежда рода

Решетов Евгений Валерьевич
1. Жребий некроманта
Фантастика:
фэнтези
попаданцы
6.50
рейтинг книги
Жребий некроманта. Надежда рода

Кодекс Охотника. Книга XXI

Винокуров Юрий
21. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XXI

Волк: лихие 90-е

Киров Никита
1. Волков
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волк: лихие 90-е

Таблеточку, Ваше Темнейшество?

Алая Лира
Любовные романы:
любовно-фантастические романы
6.30
рейтинг книги
Таблеточку, Ваше Темнейшество?

Огни Аль-Тура. Желанная

Макушева Магда
3. Эйнар
Любовные романы:
любовно-фантастические романы
эро литература
5.25
рейтинг книги
Огни Аль-Тура. Желанная

Возвышение Меркурия

Кронос Александр
1. Меркурий
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия

Камень. Книга 3

Минин Станислав
3. Камень
Фантастика:
фэнтези
боевая фантастика
8.58
рейтинг книги
Камень. Книга 3

Раб и солдат

Greko
1. Штык и кинжал
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Раб и солдат

Прометей: Неандерталец

Рави Ивар
4. Прометей
Фантастика:
героическая фантастика
альтернативная история
7.88
рейтинг книги
Прометей: Неандерталец

Титан империи 7

Артемов Александр Александрович
7. Титан Империи
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Титан империи 7

Низший - Инфериор. Компиляция. Книги 1-19

Михайлов Дем Алексеевич
Фантастика 2023. Компиляция
Фантастика:
боевая фантастика
5.00
рейтинг книги
Низший - Инфериор. Компиляция. Книги 1-19

Сын Петра. Том 1. Бесенок

Ланцов Михаил Алексеевич
1. Сын Петра
Фантастика:
попаданцы
альтернативная история
6.80
рейтинг книги
Сын Петра. Том 1. Бесенок

Последний попаданец 5

Зубов Константин
5. Последний попаданец
Фантастика:
юмористическая фантастика
рпг
5.00
рейтинг книги
Последний попаданец 5