методи запиту

Книга розрахована на широке коло Новомосковсктелей, хто цікавиться програмуванням на C # .Введіте сюди коротку анотацію
Книга: C # 4.0: повне керівництво
методи запиту
Розділи на цій сторінці:
Синтаксис запиту, описаний в попередніх розділах, застосовується при формуванні більшості запитів в С #. Він зручний, ефективний і компактний, хоча і не є єдиним способом формування запитів. Інший спосіб полягає у використанні методів запиту. які можуть бути викликані будь-якого рахункового об'єкта, наприклад масиву.
Основні методи запиту
Методи запиту визначаються в класі System.Linq.Enumerable і реалізуються у вигляді методів розширення функцій узагальненої форми інтерфейсу 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
де TResult позначає тип результату, який дає делегат, а Т - тип елемента. У методах запиту аргументи selector. predicate або keySelector визначають дію, яке робить метод запиту. Наприклад, в методі Where () аргумент predicate визначає порядок відбору даних в запиті. Кожен метод запиту повертає перелічувальний об'єкт. Тому результат виконання одного методу запиту можна використовувати для виклику іншого, поєднуючи ці методи в ланцюжок.
Метод Join () приймає чотири аргументи. Перший аргумент (inner) являє собою посилання на другу об'єднує послідовність, а першою є послідовність, для якої викликається метод Join (). Селектор ключа для першої послідовності передається в якості аргументу outerKeySelector, а селектор ключа для другої послідовності - як аргумент innerKeySelector. Результат об'єднання позначається як аргумент resultSelector. Аргумент outerKeySelector має тип Func
Аргумент методу запиту є метод, сумісний з вказується формою делегата Funс. але він не обов'язково повинен бути явно декларуються методом. Насправді замість нього найчастіше використовується лямбда-вираз. Як пояснювалося в розділі 15, лямбда-вираз забезпечує більш простий, але ефективний спосіб визначення того, що, по суті, є анонімним методом, а компілятор C # автоматично перетворює лямбда-вираз в форму, яка може бути передана в якості параметра делегату Funс. Завдяки тому що лямбда-вирази забезпечують більш простий і раціональний спосіб програмування, вони використовуються у всіх прикладах, представлених далі в цьому розділі.
Формування запитів за допомогою методів запиту
Використовуючи методи запиту одночасно з лямбда-виразами, можна формувати запити, взагалі не користуючись синтаксисом, передбаченим в C # для запитів. Замість цього досить викликати відповідні методи запиту. Звернемося спочатку до простого прикладу. Він являє собою варіант першого прикладу програми з цієї глави, перероблений з метою продемонструвати застосування методів запиту Where () і Select () замість відповідних операторів.
// Використовувати методи запиту для формування простого запиту.
// Це перероблений варіант першого прикладу програми з цього розділу.
using System;
using System.Linq;
class SimpQuery
static void Main ()
int [] nums = <1, -2, 3, 0, -4, 5>;
// Використовувати методи Where () і Select () для
// формування простого запиту.
var posNums = nums.Where (n => n> 0) .Select (r => r);
Console.Write ( "Позитивні значення з масиву nums:");
// Виконати запит і вивести його результати,
foreach (int i in posNums) Console.Write (i + "");
Console.WriteLine ();
>
>
Ця версія програми дає такий же результат, як і вихідна.
Позитивні значення з масиву nums 1 3 5
Зверніть особливу увагу в цій програмі на наступний рядок коду.
var posNums = nums.Where (n => n> 0) .Select (r => r);
У цьому рядку коду формується запит, який зберігається в змінної posNums. За цим запитом, в свою чергу, формується послідовність позитивних значень, які з масиву nums. Для цієї мети служить метод Where (). відбирає запитувані значення, а також метод Select (). вибірково формує з цих значень остаточний результат. Метод Where () може бути викликаний для масиву nums. оскільки у всіх масивах реалізується інтерфейс IEnumerable
Формально метод Select () в розглянутому тут прикладі не потрібен, оскільки це простий запит. Адже послідовність, яка повертається методом Where (). вже містить кінцевий результат. Але остаточний вибір можна зробити і по більш складного критерію, як це було показано раніше на прикладах використання синтаксису запитів. Так, за наведеним нижче запитом з масиву nums повертаються позитивні значення, збільшені на порядок величини.
var posNums = nums.Where (n => n> 0) .Select (r => r * 10);
Як і слід було очікувати, в ланцюжок можна об'єднувати і інші операції над даними, які отримуються за запитом. Наприклад, за таким запитом вибираються позитивні значення, які потім сортуються в порядку спадання і повертаються у вигляді результуючої послідовності:
var posNums = nums.Where (n => n> 0) .OrderByDescending (j => j);
де вираз j => j позначає, що впорядкування залежить від вхідного параметра, який є елементом даних з послідовності, одержуваної з методу Where ().
У наведеному нижче прикладі демонструється застосування методу запиту GroupBy (). Це змінений варіант представленого раніше прикладу.
// Продемонструвати застосування методу запиту GroupBy ().
// Це перероблений варіант прикладу, представленого раніше
// для демонстрації синтаксису запитів.
using System;
using System.Linq;
class GroupByDemo
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 = websites.Where (w => w.LastIndexOf ( '.')! = 1).
GroupBy (x => x.Substring (x.LastIndexOf ( ".", X.Length)));
// Виконати запит і вивести його результати, foreach (var sites in webAddrs)
foreach (var sites in webAddrs)
Console.WriteLine ( "Веб-сайти, згруповані" +
"По імені домена" + sites.Key);
foreach (var site in sites)
Console.WriteLine ( "" + site);
Console.WriteLine ();
>
>
>
Ця версія програми дає такий же результат, як і попередня. Єдина відмінність між ними полягає в тому, як формується запит. У даній версії для цієї мети використовуються методи запиту.
Розглянемо ще один приклад. Але спочатку наведемо ще раз запит з представленого раніше прикладу застосування оператора join.
var inStockList = from item in items
join entry in statusList
on item.ItemNumber equals entry.ItemNumber
select new Temp (item.Name, entry.InStock);
За цим запитом формується послідовність, що складається з об'єктів, інкапсулюючих найменування товару і стан його запасів на складі. Вся ця інформація виходить шляхом об'єднання двох джерел даних: items і statusList. Нижче наведено перероблений варіант даного запиту, в якому замість синтаксису, передбаченого в C # для запитів, використовується метод запиту Join ().
// Використовувати метод запиту Join () для складання списку
// найменувань товарів і стану їх запасів на складі,
var inStockList = items.Join (statusList,
kl => kl.ItemNumber,
k2 => k2.ItemNumber,
(Kl, k2) => new Temp (kl.Name, k2.InStock));
В даному варіанті іменований клас Temp використовується для зберігання результуючого об'єкта, але замість нього можна скористатися анонімним типом. Такий варіант запиту наведено нижче.
Синтаксис запитів і методи запиту
Як пояснювалося в попередньому розділі, запити в C # можна формувати двома способами, використовуючи синтаксис запитів або методи запиту. Цікаво, що обидва способи пов'язані один з одним більш тісно, ніж здається, дивлячись на вихідний код програми. Справа в тому, що синтаксис запитів компілюється в виклики методів запиту. Тому код
буде перетворений компілятором в наступний виклик.
Таким чином, обидва способи формування запитів в кінцевому підсумку сходяться на одному і тому ж.
Але якщо обидва способи виявляються в кінцевому рахунку рівноцінними, то який з них краще для програмування на С #? В цілому, рекомендується частіше користуватися синтаксисом запитів, оскільки він повністю інтегрований в мову С #, підтримується відповідними ключовими словами і синтаксичними конструкціями.
Додаткові методи розширення, пов'язані із запитами
Крім методів, відповідних операторам запиту, підтримуваним в С #, име-ється ряд інших методів розширення, пов'язаних із запитами і часто надають допомогу у формуванні запитів. Ці методи надаються в середовищі .NET Framework і визначені для інтерфейсу IEnumerable
метод Опис
All (predicate) Повертає логічне значення true,
якщо всі елементи в послідовності
задовольняють умові, що задається параметром
predicate
Any (predicate) Повертає логічне значення true, якщо
будь-який елемент в послідовності задовольняє
умові, що задається параметромpredicate
Average () Повертає середнє всіх значень в числовий
послідовності
Contains (value) Повертає логічне значення true, якщо
в послідовності міститься вказаний об'єкт
Count () Повертає довжину послідовності, тобто
кількість складових її елементів
First () Повертає перший елемент в послідовності
Last () Повертає останній елемент в послідовності
Max () Повертає максимальне значення в
послідовності
Min () Повертає мінімальне значення в
послідовності
Sum () Повертає суму значень в числовий
послідовності
Метод Count () вже демонструвався раніше в цій главі. А в наступній програмі демонструються інші методи розширення, пов'язані із запитами.
// Використовувати ряд методів розширення, визначених у класі Enumerable.
using System;
using System.Linq;
class ExtMethods
static void Main ()
int [] nums = <3, 1, 2, 5, 4>;
Console.WriteLine ( "Мінімальним значенням є" + nums.Min ());
Console.WriteLine ( "Максимальне значення становить" + nums.Max ());
Console.WriteLine ( "Перше значення дорівнює" + nums.First ());
Console.WriteLine ( "Останнє значення дорівнює" + nums.Last ());
Console.WriteLine ( "Сумарне значення дорівнює" + nums.Sum ());
Console.WriteLine ( "Середнє значення дорівнює" + nums.Average ());
if (nums.All (n => n> 0))
Console.WriteLine ( "Все значення більше нуля.");
if (nums.Any (n => (n% 2) == 0))
Console.WriteLine ( "Принаймні одне значення є парним.");
if (nums.Contains (3))
Console.WriteLine ( "Масив містить значення 3.");
>
>
Ось до якого результату приводить виконання цієї програми.
Мінімальним значенням є 1
Максимальне значення становить 5
Перше значення дорівнює 3
Останнє значення дорівнює 4
Сумарне значення дорівнює 15
Середнє значення дорівнює 3
Всі значення більше нуля.
Принаймні одне значення є парним
Масив містить значення 3.
Методи розширення, пов'язані із запитами, можна також використовувати в самому запиті, грунтуючись на синтаксисі запитів, передбаченому в С #. І в дійсності це робиться дуже часто. Наприклад, метод Average () використовується в наведеній нижче програмі для отримання послідовності, що складається тільки з тих значень, які виявляються менше середнього всіх значень в масиві.
При виконанні цієї програми виходить наступний результат.
Середнє значення дорівнює 5.6
Значення менше середнього: 1 2 4 3
Зверніть особливу увагу в цій програмі на наступний код запиту.
Як бачите, змінної x в операторі let присвоюється середнє всіх значень в масиві nums. Це значення виходить в результаті виклику методу Average () для масиву nums.