Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 142
Текст из файла (страница 142)
Излишне говорить, что расширяющие методы ЕпцвегзЬ1е и СцетуаЬ1е очень полезны и вне контекста Ы((й. И по правде говоря, некоторая функциональность, предоставленная расширяющими методами, не имеет соответствующих ключевых слов, а потому может использоваться только прямыми вызовами расширяющих методов.
Стандартные операции запросов Язык Ы)))й построен на использовании стандартных операций запросов, которые представляют собой методы, предназначенные для операций с последовательностями наподобие коллекций, которые реализуют интерфейсы 1ЕпцвегзЬ1е и 10цетуаЬ1е. Как описывалось ранее, когда компилятор С№ встречает выражение запроса, то обычно преобразует его в последовательность или цепочку запросов расширяющих методов, реализующих нужное поведение. У такого подхода есть два преимущества.
Одно состоит в том, что в общем можно выполнять те же действия, что и выражение запроса Ыг)ь), явно вызывая расширяющие методы. Результирующий код не так легко читать. как код с выражениями запросов. Однако бывают случаи, когда нужна функциональность расширяющих методов, а полное выражение запроса может быть излишним. Также она необходима тогда, когда операции запросов не имеют соответствующих ключевых слов. Самое большое преимущество такого подхода связано с расширяемостью ЫВ(Я.
Это значит, что можно определить собственный набор расширяющих методов, а компилятор сгенерирует их вызовы при компиляции выражения запроса Ы)))Я. Например, предположим, что вместо импортирования пространства имен Буякев. Ь№пс( и решено предоставить собственную реализацию Мнете и яе1есс. Это можно сделать следующим образом: ц*1по Яуягевг ця1пд Яуякев.со11ест1опя.оепет1сг рцв11с ягаг1с с1яяя Музг(озег ( рцЬ1тс ягяттс 1ЕпцвегзЬ1е<Т> Кпеге<Т> ( Спгя 1ЕпцвегзЬ1е<Т> яоцгсе, яуятев.Гцпс<Т,Ьоо1> Ргег(1сзге ) ( Сопяо1е.кттгеьгпе( "Вызвана собственная реализация Кьете." ) гегцгп Яуятев.ЬЬп<(.ЕпцветаЬ1е.янеке( ясцгсе, ргебтсате )Г ) рцьзтс ясзс1с 1епцвегяьзе<е> Бе1есг<т,е> ( Готя 1ЕпцвягяЬ1е<Т> яоцгсе, яуясев.гцпс<т,е> яе1ессот ) ( Сопяо1е.кг1теЬтпе( "Вызвана собственная реализация Яе1есс." ) геьцгп Яуятев.ЬЬпг(.ЕпцвегзЬ1е.зе1еск( яоцгсе, яе1естог ); 530 Глава (6 риЫ1с с1азз Сизсовзцо ( зсасгс яогб Мага() ( гпс(] пивЬегз = ( 1, 2, 3, 4 яаг с(иегу = гсов х 1п пип|Ьегз нпеге х $2 == О зе1есс х * 2; гогеась( яаг 1сев гп Чиегу ) ( Сопзо1е.кг1Ге) Ьпе( 1сев ); Обратите внимание, что импортировать пространство имен Буз сев.
11по не понадобилось. Помимо дополнительного удобства это подтверждает слова о том, что отказ от импорта пространства имен Бузгев. 11пс( предотвращает автоматическое нахождение компилятором расширяющих методов Бузгев. Б1по. епивегаь1е. В статическом классе МуБс(оБес предоставлена собственная реализация стандартных операций запросов КЬеге и Бе1есг, которые просто протоколируют сообщение и затем пересылают его операциям из ЕпивегаЬ1е.
Если запустить этот код. то получится следующий вывод: Вызвана собственная реализация Кпеге. Вызвана собственная реализация Бе1есс. я 8 Упражнение можно немного усложнить, использовав ЫМЯ с коллекцией, которая не поддерживает 1ЕпивегаЬ1е. Хотя обычно 1ЕпивегаЬ1е в коллекциюс реализуется, для наглядности предположим, что вместо нее поддерживается пользовательский интерфейс 1МуЕпивагаЬ1е.
В данном случае можно обеспечить собственный набор операций запросов, работаюпщх с 1МуЕпивагаЬ1е вместо 1ЕпивагаЫе. Однако здесь есть один минус. Если типы не унаследованы от 1ЕпивагаЬ1е или 1ЕпивагаЬ1е<Т>, то использовать Ы)ЧЯ не удастся, потому что конструкция Ггов требует источника данных, реализующего 1ЕпивегаЬ1е. Тем не менее. нужного эффекта можно достичь, вызвав стандартные операции запросов на типе 1МуепивагаЬ1е. Пример будет показан в разделе "Приемы функционального программирования" далее в главе, где в качестве основы будет взят пример из главы 14. Ключевые слова запросов СФ В СЗ 2008 появился небольшой набор новых ключевых слов для создания выражений запросов Ы)))о,часть которых уже встречались в прелы)бчцих разделах: Ггов, Ооыь ньеге, огоир. 1пго, 1ес, азсепг(1пи,с(езсепс(1по, оп,еоиа1з, ьу, ьп, огбегьу и эе1есг.
Об их применении речь пойдет в последующих разделах. Конструкция й~ов и переменные диапазона Каждуяй запрос начинается со слова ггов. Конструкция Ггов — это генератор, который также определяет переменную диапазона — локальную переменную, используемую для представления каждого элемента входной коллекции, по мере применения к нему выражения запроса. Конструкция 1гов похожа на оператор Богеасб в стиле императивного программирования, а переменная диапазона идентична по своему предназначению переменной итерации в том же Гогеасб. 'с)М0: язык интегрированных запросов 631 Выражение запроса может содержать более одной конструкции Тгоис В таком случае имеется более одной переменной диапазона, что является аналогом вложенных операторов Тогеасп.
В следующем примере используется несколько конструкций Тгоиг для генерации хорошо известной из начальной школы таблицы умножения, хотя и не в табличном формате: ив1пс Яувгетю ивспд Яувсеа.псппг ривуас с1ввв Ми1СТвЬ1е ( вгаг1с го1б Мвап() чаг «Рхегу ггот х 1п ЕппвегаЬ1е.каппе(0,10] ггое у хп ЕгшшегаЬ1е.каиса(0, 10] зе1есе пен ( Х к, у=у, Ргобпсе х * у )г Гогеаси( иаг ТСес 1п пиесу ) ( Сопво1е.нгьгеьапе( "(0) * (1) = (2)", Тгеа.Х, Тгеа.у, 1 еа.ргобисС )Г ) ) ) Как вы должны помнить, выражения ЫХЯ компилируются в строго типизированный код. Так каковы же типы х и у в данном примере? Компилятор выводит типы этих двух переменных диапазона на основе типа аргумента интерфейса 1ЕпипегаЬ1е<Т>, возвращенного Каппе. Поскольку Каппе возвращает тип 1ЕпитегвЬ1е<апс>,типом хи у является ).пс.
Теперь может возникнуть вопрос, что произойдет, если выражение запроса будет применено к коллекции, поддерживающей только необобщенный интерфейс 1ЕпшиегвЬ1е? В таких случаях должен быть явно указан тип переменной диапазона: ив1пз Яувсепг ивапч Яувгеа.йспг)г ивано Яувгеа.Со11есгтопвг риЬ11с с1авв Иопоеиегтсиспо всагьс гоги Мати() ( АггэуЬТвС пиаЬегв = пен Аггауьввг() пиэпегв.йбб( 1 ); пиаЬегв.ибб( 2 гвг Чиегу = Тиос хпг и Тп пиаЬегв ве1есг п * 2," гогевсп( чвг Тсет 1п г)вегу ) ( Сопво1е.игТСЕЬТпе( 1Сет )г Здесь тип переменной диапазона п указан явно — ).пс. Во время выполнения осуществляется приведение. которое может закончиться неудачей с генерацией исключения 1пуа11бСазСЕхсергаоп.
Поэтому лучше стремиться к использованию вместо 1ЕпиаегаЬ1е обобщенного, строго типизированного интерфейса 1ЕпиигегвЬ1е<Т>, что позволит перехватить ошибки подобного рода на этапе компиляции, а не выполнения. 532 Глава 16 На заметку! На протяжении всей книги постоянно подчеркивается, что компилятор — ваш лучший друг.
Старайтесь использовать максимум его возможностей для перехвата ошибок кодирования во время компиляции, а не во время выполнения. Строго типизированные языки, такие как СВ, при проверке целостности операций, выполняемых над типами, которые определены в коде, полагаются на компилятор. Отбросив конкретный тип и работая с общими типами вроде Я уз Сев. ОЬ 3 ес С, а не с конкретными типами объектов, вы тем самым отказываетесь от одной из самых мощных возможностей компилятора. Если в коде присутствует ошибка, связанная с типами, и служба контроля качества не обнаружит ее до выпуска программы, можно биться об заклад, что заказчик даст вам знать об этом, возможно, даже не в самой вежливой форме! Конструкция 1охп Вслед за ухов может использоваться конструкция 3 о1п для сопоставления данных из двух различных источников.
Операции соединения (3оьп) обычно не обязательны в средах, где объекты связываются в иерархии и другие ассоциативные отношения. Однако в мире реляционных баз данных обычно не существует жестких связей между элементами двух разных коллекций, или таблиц, помимо эквивалентности между элементами внутри каждой записи. Эта операция эквивалентности определяется при создании конструкции 3 ойп. Рассмотрим следующий пример: ця1по ЯуяСев; цяупс Яуягев.ЬЬпц! цязпд яуяпев.со11есС1опя.яепег1с; рцЬ11с с1аяя Евр1оуее1О ( рцЬ11с ясг1по 1О ( оеьг яепг ) рцЬ11с ятгзпд паве ( оеС; яеС1 ) рцЬ11с с1аяя Евр1оуеенаСЬопа11Су ( рцвьэс яСсспя 1г( ( деС1 яеСг ) рцЬ11с яггэ В МаСЕопа11Су ( ОЕС1 ЯЕС1 ) ) рцЬ11с с1аяя ЮоьпЕхавр1е ( ясасус чосб Маса() ( ГГ Построить коллекцию сотрудников.
тат евр1оуеея = пен ЬьяС<Евр1оуеетп>() Евр1оуеет<(( 1с( = "111-11-1111", Маве = "Ег( 01аяяег" ), пен Евр1оуее1с(( 1с( = "222-22-2222", паве = "Ярац1г(1по Ява11я" ), пен Евр1оуее1г(( 1О = "333-33-3333", Мап1е = "1тап 1чапоч" ), пен Е р1оу 1О( 1О = "ЛЛЛ-ЛЧ-ЛЧЧЛ", паве = "Чаяуа Рцркьп" ) )г г'/ Построить коллекцию национальностей. чаг еврнаСЬопа1111ея = пен ЬуяС<Евр1оуееМаСЬопа11зу> () пен Евр1оуеенаС1опа11Су( 1с( = "111-11-1111", МаС1опа11Су = "Авегьсап" ), пен Евр1оуеенаС1опа11Су( 1г( = "333-33-3333", Магьопа11Су = "Кцяя1ап" ), ВМ0: язык ннтегрнроввннык запросов 533 пен Етр1оуееняквопа11ку( 14) = "222-22-2222", Мак1опя11ку = "тгьяп" ), и Епр1оуееняк'опаувку) 1г) = "444-44-4444", Мяк1опя11ку = "Нияявап" ) )' г'г' Построить запрос.
чаг г)иегу = вгоп епр 1п еир1оуеея 3овп и Еп еярнас1опа11Е1ея оп евр.16 ек)иа1я п.16 огаегЪу п.наквопа11су деясепг)1пи яе1еск пен ) 14) = етр.1г), Мате = евр.нэпе, Маквопа11ту = п.няквопя11ку )г гогеясЪ) чяг регяоп вп Пиесу ) ( сопяо1е.нг1КЕ11пе( "(О), )1), 1С)2)", регяоп.1т), регяоп.нате, регяоп.наквопа11ку )т ) ) ) В примере присутствуют две коллекции. Первая содержит сотрудников с их идентификационными номерами. Вторая коллекция хранит национальности сотруднинов, причем каждый сотрудник указывается только его идентификатором. Чтобы не усложнять пример, каждая порция данных относится к типу я кг1птт. Теперь требуется получить список имен всех сотрудников вместе с их национальностями, при этом отсортировав список по национальностям в порядке по убыванию. Конструкция 3 овп здесь нужна потому.
что необходимая информация содержится в более чем одном источнике данных. Она позволяет объединить информацию из двух источников данных, и с помощью Ы)т)Ь) это делается очень легко. В выражении запроса конструкцию 3овп выделена полужирным. Для каждого элемента, на который ссылается переменная диапазона еар )т.е. для каждого элемента из егир1оуеея), находится элемент в коллекции епрыаяхопа1111ея )представленной переменной диапазона и), где 14) эквивалентно 14), на который ссылается епр. Затем конструкция проекции яе1еск при построении результата берет данные из обеих коллекций и проектирует нх на анонимный тип. Таким образом, результатом запроса является единственная коллекция, в ноторой элементы из епр1оуее и еармасвопа1111ея объединяются в один.
Если запустить этот пример, получится следующий результат: 333-33-3333, 1чяп 1чапоч, Нияявап 444-44-4444, Чаяуа Рирх1п, Кияявап 222-22-2222, Браи1атпд Бая11я, 1гвяп 111-11-1111, Ег) 61яяяек, Атег1сап Когда запрос содержит операцию 3о1п, компилятор "за кулисами" преобразует ее в вызов расширяющего метода,то).п, если только за ней не следует конструнция 1псо. При наличии ).псо компилятор использует расширяющий метод сгоир,товп, который также группирует результаты. Подробную информацию о более экзотических вещах, которые можно делать с помощью конструкций 3 о я и и 1пео, ищите в документации по ы)т)Я в мЗВ)т) или же в книге Джозефа Раттца-мл.












