программирование. Руководство su P# a n Reference в herbert schildt полное руководство с 0 герберт шилдт
Скачать 3.32 Mb.
|
Ниже приведена программа, демонстрирующая другое применение оператора select. В этой программе сначала создается класс EmailAddress, содержащий два свойства. В первом из них хранится имя адресата, а во втором – адрес его электронной почты. Затем в этой программе создается массив, содержащий несколько элементов данных типа EmailAddress. И наконец, в данной программе создается список, состоящий только из адресов электронной почты, извлекаемых по запросу. // Возвратить часть значения переменной диапазона. using System; using System.Linq; class EmailAddress { public string Name { get; set; } public string Address { get; set; } public EmailAddress(string n, string a) { Name = n; Address = a; } } class SelectDemo2 { static void Main() { EmailAddress[] addrs = { new EmailAddress("Герберт", "Herb@HerbSchildt.com"), new EmailAddress("Tom", "Tom@HerbSchildt.com"), new EmailAddress("Capa", "Sara@HerbSchildt.com") }; // Сформировать запрос на получение адресов // электронной почты. var eAddrs = from entry in addrs select entry.Address; Console.WriteLine("Адреса электронной почты:"); // Выполнить запрос и вывести его результаты, foreach(string s in eAddrs) Console.WriteLine(" " + s); } } Вот к какому результату приводит выполнение этой программы. Адреса электронной почты: Herb@HerbSchildt.com Tom@HerbSchildt.com Sara@HerbSchildt.com Обратите особое внимание на следующий оператор select, select entry.Address; Вместо полного значения переменной диапазона этот оператор возвращает лишь его адресную часть (Address). Это означает, что по данному запросу возвращается последовательность символьных строк, а не объектов типа Email Address. Именно поэтому переменная s указывается в цикле foreach как string. Ведь как пояснялось ранее, тип последовательности результатов, возвращаемых по запросу, определяется типом значения, возвращаемым оператором select. Одной из самых эффективных для оператора select является возможность возвращать последовательность результатов, содержащую элементы данных, формируемые во время выполнения запроса. В качестве примера рассмотрим еще одну программу. В ней определяется класс Contactlnfo, в котором хранится имя, адрес электронной почты и номер телефона адресата. Кроме того, в этой программе определяется класс Email Addr ess, использовавшийся в предыдущем примере. В методе Main () создается массив объектов типа Contactlnfo, а затем объявляется запрос, в котором источником данных служит этот массив, но возвращаемая последовательность результатов содержит объекты типа EmailAddress. Таким образом, типом последовательности результатов, возвращаемой оператором select, является класс EmailAddress, а не класс Contactlnfo, причем его объекты создаются во время выполнения запроса. // Использовать запрос для получения последовательности объектов // типа EmailAddresses из списка объектов типа Contactlnfo. using System; using System.Linq; class Contactlnfo { public string Name { get; set; } public string Email { get; set; } public string Phone { get; set; } public Contactlnfo(string n, string a, string p) { Name = n; Email = a; Phone = p; } } class EmailAddress { public string Name { get; set; } public string Address { get; set; } public EmailAddress(string n, string a) { Name = n; Address = a; } ‑ } class SelectDemo3 { static void Main() { Contactlnfo[] contacts = { new Contactlnfo("Герберт", " Herb@HerbSchildt.com ", "555‑1010"), new Contactlnfo("Том", " Tom@HerbSchildt.com ", "555‑1101"), new Contactlnfo("Capa", " Sara@HerbSchildt.com ", "555‑0110") }; • // Сформировать запрос на получение списка объектов типа EmailAddress. var emailList = from entry in contacts select new EmailAddress(entry.Name, entry.Email); Console.WriteLine("Список адресов электронной почты:"); // Выполнить запрос и вывести его результаты, foreach(EmailAddress е in emailList) Console.WriteLine(" {0}: {1}", e.Name, e.Address ); } } Ниже приведен результат выполнения этой программы. • Список адресов электронной почты: Герберт: Herb@HerbSchildt.com Том: Tom@HerbSchildt.com Сара: Sara@HerbSchildt.com Обратите особое внимание в данном запросе на следующий оператор select. select new EmailAddress(entry.Name, entry.Email); В этом операторе создается новый объект типа EmailAddress, содержащий имя и адрес электронной почты, получаемые из объекта типа Contactlnfo, хранящегося в массиве contacts. Но самое главное, что новые объекты типа EmailAddress создаются в операторе select во время выполнения запроса. Применение вложенных операторов from Запрос может состоять из нескольких операторов‑ f г от, которые оказываются в этом случае вложенными. Такие операторы from находят применение в тех случаях, когда по запросу требуется получить данные из двух разных источников. Рассмотрим простой пример, в котором два вложенных оператора from используются в запросе для циклического обращения к элементам двух разных массивов символов. В итоге по такому запросу формируется последовательность результатов, содержащая все возможные комбинации двух наборов символов. // Использовать два вложенных оператора from для составления списка // всех возможных сочетаний букв А, В и С с буквами X, Y и Z. using System; using System.Linq; // Этот класс содержит результат запроса, class ChrPair { public char First; public char Second; public ChrPair(char c, char c2) { First = c; Second = c2; } } class MultipleFroms { static void Main() { char[] chrs = { 'A', 1В', 'C' }; char[] chrs2 = { 'X', 1Y', 'Z' }; // В первом операторе from организуется циклическое обращение //к массиву символов chrs, а во втором операторе from – // циклическое обращение к массиву символов chrs2. var pairs = from chi in chrs from ch2 in chrs2 select new ChrPair(chl, ch2); Console.WriteLine("Все сочетания букв ABC и XYZ: "); foreach(var p in pairs) Console.WriteLine("{0} {1}", p.First, p.Second); } } Выполнение этого кода приводит к следующему результату. Все сочетания букв ABC и XYZ: А X A Y A Z В X В Y В Z С X С Y С Z Этот пример кода начинается с создания класса ChrPair, в котором содержатся результаты запроса. Затем в нем создаются два массива, chrs и chrs 2, и, наконец, формируется следующий запрос для получения всех возможных комбинаций двух последовательностей результатов. var pairs = from chi in chrs from ch2 in chrs2 select new ChrPair(chi, ch2); Во вложенных операторах from организуется циклическое обращение к обоим массивам символов, chrs и chrs2. Сначала из массива chrs получается символ, сохраняемый в переменной chi. Затем перечисляется содержимое массива chrs2. На каждом шаге циклического обращения во внутреннем операторе from символ из массива chrs2 сохраняется в переменной ch2 и далее выполняется оператор select. В результате выполнения оператора select создается новый объект типа ChrPair, содержащий пару символов, которые сохраняются в переменных chi и ch2 на каждом шаге циклического обращения к массиву во внутреннем операторе from. А в конечном итоге получается объект типа ChrPair, содержащий все возможные сочетания извлекаемых символов. Вложенные'операторы from применяются также для циклического обращения к источнику данных, который содержится в другом источнике данных. Соответствующий пример приведен в разделе "Применение оператора let для создания временной переменной в запросе" далее в этой главе. Группирование результатов с помощью оператора group Одним из самых эффективных средств формирования запроса является оператор group, поскольку он позволяет группировать полученные результаты по ключам. Используя последовательность сгруппированных результатов, можно без особого труда получить доступ ко всем данным, связанным с ключом. Благодаря этому свойству оператора group доступ к данным, организованным в последовательности связанных элементов, осуществляется просто и эффективно. Оператор group является одним из двух операторов, которыми может оканчиваться запрос. (Вторым оператором, завершающим запрос, является select.) Ниже приведена общая форма оператора group. group переменная_диапазона by ключ Этот оператор возвращает данные, сгруппированные в последовательности, причем каждую последовательность обозначает общий ключ. Результатом выполнения оператора group является последовательность, состоящая из элементов типа IGrouping Ниже приведен пример, демонстрирующий применение оператора group. В коде этого примера сначала объявляется массив, содержащий список веб‑сайтов, а затем формируется запрос, в котором этот список группируется по имени домена самого верхнего уровня, например . org или . сот. // Продемонстрировать применение оператора group. using System; using System.Linq; class GroupDemo { static void Main() { string[] websites = { "hsNameA.com", "hsNameB.net", "hsNameC.net", "hsNameD.com", "hsNameE.org", "hsNameF.org", "hsNameG.tv", "hsNameH.net", "hsNamel.tv" }; // Сформировать запрос на получение списка веб‑сайтов, // группируемых по имени домена самого верхнего уровня. var webAddrs = from addr in websites where addr.LastlndexOf('.') != ‑1 group addr by addr.Substring(addr.LastlndexOf('.')); // Выполнить запрос и вывести его результаты, foreach(var sites in webAddrs) { Console.WriteLine("Веб‑сайты, сгруппированные " + "по имени домена" + sites.Key); foreach(var site in sites) Console.WriteLine (" " + site); Console.WriteLine(); } } } Вот к какому результату приводит выполнение этого кода. Веб‑сайты, сгруппированные по имени домена .сот hsNameA.сот hsNameD.сот Веб‑сайты, сгруппированные по имени домена .net hsNameB.net hsNameC.net hsNameH.net * Веб‑сайты, сгруппированные по имени домена .org hsNameE.org hsNameF.org Веб‑сайты, сгруппированные по имени домена .tv hsNameG.tv hsNamel.tv Как следует из приведенного выше результата, данные, получаемые по запросу, группируются по имени домена самого верхнего уровня в адресе веб‑сайта. Обратите внимание на то, как это делается в операторе group из следующего запроса. var webAddrs = from addr in websites where addr.LastlndexOf('.') != ‑1 group addr by addr.Substring(addr.LastlndexOf('.')); Ключ в этом операторе создается с помощью методов LastlndexOf () и Substring () , определенных для данных типа string. (Эти методы упоминаются в главе 7, посвященной массивам и строкам. Вариант метода Substring () , используемый в данном примере, возвращает подстроку, начинающуюся с места, обозначаемого индексом, и продолжающуюся до конца вызывающей строки.) Индекс последней точки в адресе веб‑сайта определяется с помощью метода LastlndexOf () . По этому индексу в методе Substring () создается оставшаяся часть строки, в которой содержится имя домена самого верхнего уровня. Обратите внимание на то, что в операторе where отсеиваются все строки, которые не содержат точку. Метод LastlndexOf () возвращает ‑1, если указанная подстрока не содержится в вызывающей строке. Последовательность результатов, получаемых при выполнении запроса, хранящегося в переменной webAddrs, представляет собой список групп, поэтому для доступа к каждому члену группы требуются два цикла foreach. Доступ к каждой группе осуществляется во внешнем цикле, а члены внутри группы перечисляются во внутреннем цикле. Переменная шага внешнего цикла foreach должна быть экземпляром интерфейса I Grouping, совместимым с ключом и типом элемента данных. В рассматриваемом здесь примере ключи и элементы данных относятся к типу string. Поэтому переменная sites шага внешнего цикла имеет тип IGrouping foreach(IGrouping Console.WriteLine("Веб‑сайты, сгруппированные " + "по имени домена" + sites.Key); foreach(string site in sites) Console.WriteLine(" " + site); Console.WriteLine (); } Продолжение запроса с помощью оператора into При использовании в запросе оператора select или group иногда требуется сформировать временный результат, который будет служить продолжением запроса для получения окончательного результата. Такое продолжение осуществляется с помощью оператора into в комбинации с оператором select или group. Ниже приведена общая форма оператора into: into имя тело_запроса где имя обозначает конкретное имя переменной диапазона, используемой для циклического обращения к временному результату в продолжении запроса, на которое указывает тело_запроса. Когда оператор into используется вместе с оператором select или group, то его называют продолжением запроса, поскольку он продолжает запрос. По существу, продолжение запроса воплощает в себе принцип построения нового запроса по результатам предыдущего. ПРИМЕЧАНИЕ Существует также форма оператора into, предназначенная для использования вместе с оператором join, создающим групповое объединение, о котором речь пойдет далее в этой главе. Ниже приведен пример программы, в которой оператор into используется вместе с оператором group. Эта программа является переработанным вариантом предыдущего примера, в котором список веб‑сайтов формируется по имени домена самого верхнего уровня. А в данном примере первоначальные результаты запроса сохраняются в переменной диапазона ws и затем отбираются для исключения всех групп, состоящих менее чем из трех элементов. // Использовать оператор into вместе с оператором group. using System; using System.Linq; class IntoDemo { static void Main() { string[] websites = { "hsNameA.com", "hsNameB.net", "hsNameC.net", "hsNameD.com", "hsNameE.org", "hsNameF.org", "hsNameG.tv", "hsNameH.net", "hsNamel.tv" }; // Сформировать запрос на получение списка веб‑сайтов, группируемых //по имени домена самого верхнего уровня, но выбрать только те // группы, которые состоят более чем из двух членов. // Здесь ws – это переменная диапазона для ряда групп, // возвращаемых при выполнении первой половины запроса, var webAddrs = from addr in websites |