Главная » C# » Выборка и изменение данных LINQ в Visual C# (Sharp)

0

При исполнении запроса LINQ обрабатываемые данные не обязательно должны оаваться в своем первоначальном виде. Скажем, что у нас имеется список клиентов, среди которых мы выбрали группу клиентов, заслуживших дополнительные очки за лояльность компании. Мы хотим отобрать этих клиентов, увеличить значение их оов, после чего возвратить список клиентов, чьи данные были изменены. Для выпоения этой задачи применяется LINQ в комбинации с методами расширения.

Возьмем, к примеру, следующее упрощенное объявление клиента:

class Customer {

public string Identifier; public int Points;

public override string ToString() {

return "Identifier (" + Identifier + ") Points (" + Points + ")";

}

}

Мы создадим список, содержащий двух клиентов, один из которых имеет очки за лльность, а другой — нет. Список создается с помощью следующего исходного кода:

List<Customer> customers = new List<Customer>() {

new Customer { Identifier = "Person 1",

P o i n t s    =    0    } ,

ne w   Custome r    {    I d e n t i f i e r   =    "Perso n   2" ,

P o i n t s    =    10 }

} ;

Клиенты с определенным количеством очков выбираются со списка, и им присвааются дополнительные очки. Для этого применяется следующий оператор LINQ:

v a r   p o i n t s    =     (fro m   custome r    i n    customer s

wher e   c u s t o m e r . P o i n t s    >    5 s e l e c t     c u s t o m e r ) . S e l e c t (

(pCustomer ,    index )    = >    { pCustomer.Point s    + =    5 ;

}) ;

r e t u r n    pCustomer ;

Запрос LINQ сочетается  с операцией модификации количества очков. Операторы LINQ from , wher e и s e l e c t не являются новыми. А вот скобки, заключающие опатор LINQ, нам еще не встречались. С помощью этих скобок указывается, что оператор LINQ является объектом, обращающимся к результирующему набору данных.

В примере для оператора (объекта) LINQ вызывается метод S e l e c t () . Посредством этого  метода  все  элементы  в  результирующем  наборе  данных  обрабатываются в цикле и передаются в качестве параметра лямбда-выражению (pCustomer) .  Вместе с каждым элементом передается его индекс в списке. Лямбда-выражение должно выполнить определенную обработку элемента и возвратить результат, который должен использоваться в качестве основы другого списка. В примере выражению передается экземпляр типа Custome r и возвращается  также  экземпляр  типа Customer . Но  до возвращения экземпляра он обрабатывается добавлением допоительных пяти бонусных очков.

Может вызвать озабоченность то обстоятельство, что не выполняется проверка, действительно ли данный клиент заслуживает бонусные очки. Но это был бы повод для озабоченности, если бы не применялось выражение LINQ, т. к. это выражение отвечает за фильтрование только тех клиентов, которые должны получить допоительные бонусные очки. Поэтому, когда вызывается  метод  Selec t о,  мы  уверы на все 100%, что дополнительные бонусные очки получат только те клиенты, которые заслуживают их. Это можно рассматривать, как создание конвейера мануляций.

Выборка посредством анонимных типов

После нахождения определенного элемента результирующий набор данных генируется с помощью оператора и метода s e l e c t () . Как было показано в предыдем разделе, оператор s e l e c t применяется для создания нового набора данных. Например, как быть, если вы хотите найти всех клиентов, отвечающих определеому критерию, но не хотите копировать все связанные данные? Возможно, вы хо-

тите получить только идентификатор клиента и накопившиеся у него очки. Для выполнения этой задачи можно было бы модифицировать часть select о операта LINQ для возвращения нового типа, объявляемого динамически.  Далее привится код предыдущего примера, модифицированный для использования анониого типа:

var points = (from customer in customers

where customer.Points > 5 select customer).Select( (customer, index) => {

customer.Points += 5; return new {

identifier = customer.Identifier, points = customer.Points };

}) ;

В данном примере ключевое слово new используется оператором return без идеификатора, но имеет синтаксис инициализатора объекта. Таким образом, объявлтся анонимный тип. Анонимный тип — это экземпляр объекта, не имеющий идеификатора. Анонимный тип имеет свойства, но не имеет методов.

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

Следующий код недопустим:

void ExampleFunction(var obj) { }

Но давайте концентрироваться на коде примера. Его можно переписать в допустой форме таким образом:

foreach(var customer in points) {

Console.WriteLine("Customer (" + customer.identifier + ")(" + customer.points + ")");

}

Компилятор, обрабатывающий выражение LINQ, знает, что конечный результующий   набор  данных  содержит  анонимные  типы  со   свойствами   identifier и points. Все это определяется, когда компилятор обрабатывает код С#.

Но что, если мы хотим манипулировать анонимным типом? Все анонимные типы являются объектами, поэтому, если объявить параметр метода или свойство как объект типа, к анонимному типу можно выполнять обращения. Но вызывать свотва identifier или points нельзя, т. к. отсутствует информация о типе. К свойсам можно обращаться посредством динамического вызова, но это сложный и меенно работающий подход. Таким образом, вкратце, при работе с анонимными типами,  не  забывайте,  что  их  можно  использовать  только  в  контексте  метода, в котором они объявлены.

17 Зак. 555

Обработка нескольких потоков

До сих пор во всех примерах использования LINQ обработке подвергался  один набор данных. LINQ  позволяет  обрабатывать  несколько  потоков  одновременно, но полученный ответ будет комбинационного типа.

Например, допустим, у нас есть следующий код LINQ:

int[] setl ={1,2,3,4 , 5} ;

int[] set2 ={1 , 2, 3, 4, 5} ;

int[] set3 = { 1, 2, 3, 4, 5 };

var triples = from a in setl from b in set2 from с in set3

select new {a , b, с };

Данному коду LINQ будет идентичен следующий псевдокод:

List<object> items = new List<object>(); foreach (int a in setl) {

foreach (int b in set2) { foreach (int с in set3) {

items.Add(new { a, b, с });

}

}

}

Когда указывается несколько операторов from, то создается механизм цикла, в кором каждый элемент обрабатывается совместно с другими элементами. Эта воожность может показаться полезной, но может иметь катастрофические стороие последствия: исполнение кажущегося простого запроса может занять намного больше времени, чем следует. Разбив запрос на отдельные операторы from, можно использовать операторы where и select в обычном порядке.

Сортировка результатов

Скорее всего, вы бы хотели получить результаты выборки в отсортированном виде. LINQ позволяет выполнять, сортировку по любому критерию. Очевидным подходом будет сортировка по цифре или букве, но можно также сортировать по длине слова.

Независимо от выбранного вида сортировки, для ее выполнения в LINQ приментся ключевое слово orderby или метод orderByO. Следующий код LINQ выпояет сортировку по алфавиту:

string[] words = { "cherry", "apple", "blueberry" };

var sortedWords = from w in words

orderby w select w;

Ключевое слово orderby вставляется перед оператором select. В данном случае, слова сортируются по алфавиту в возрастающем порядке.

Механизм работы ключевого слова orderby заключается  в сравнении значения пеменной, а не самой переменной. В данном случае идентификатор w подразумевт сортировку по полю w, но в действительности сортировка выполняется не по пю w, а по значению w.

Для сортировки в обратном порядке применяется ключевое слово descending:

var sortedWords = from w in words

orderby w descending select w;

Данный подход позволяет выполнять сортировку по другим значениям. Например, следующий код сортирует по длине слова:

var sortedWords = from w in words

orderby w.Length select w;

Ключевое слово orderby запрашивает значение w.Length, в результате чего воращается число. Если это число больше или меньше, чем длина другого слова, то сравниваемое слово помещается после или до этого слова. Обратите внимание, что можно  использовать  произвольные  значения,  не  имеющие  никакого  отношения к элементам списка, и элементы будут отсортированы в соответствии с этими прзвольными значениями.

Сортировку также можно выполнять по нескольким критериям. Например, слующий код сортирует слова сначала по алфавиту, а потом по длине:

var sortedWords = from w in words

orderby w, w.Length select w;

Для сортировки по нескольким критериям критерии добавляются к ключевому слову orderby и разделяются запятыми.

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

  • Комментарии