Секреты LINQ. Автогенерируемые свойства. Инициализаторы объектов и коллекций, страница 20

Следующий пример иллюстрирует работу цепочки extension-методов. Сначала с массивом слов работает метод Select, который превращает его в последовательность анонимных объектов. Затем выход метода Select подается на вход метода OrderBy, который сортирует последовательность по длине параметра c. Этот параметр имеет тип string и обозначает текущий элемент исходного массива строк.

static void TestSelectAnonimous()

{

string[] words = { "abstract", "false", "finally", "null", "for", "if", "object" };

var q = words.Select((c, i) => new { ID = i + 1, Length = c.Length, Word = c })

.OrderBy(c=>c.Length);

foreach (var v in q)

Console.WriteLine(v);

}

Мы рассмотрели методы проецирования Select и SelectMany и показали, что трансформирующая функция (selector) может быть задана λ-выражением, проецирующим множество элементов массива на множество анонимных объектов.

Сортировка данных

Extension-метод OrderBy имеет две сигнатуры, одна из которых имеет следущий вид.

public static IOrderedEnumerable<T> OrderBy<T, TKey>(this IEnumerable<T> source,

Func<T, TKey> keySelector);

Этот метод позволяет упорядочить входную последовательность source с помощью generic-делегата keySelector, который для каждого элемента последовательности возвращает ключ сортировки. Например, пусть задан класс Person с таким набором автогенерируемых свойств.

public class Person

{

public string Name { get; set; }

public DateTime Birth { get; set; }

public int Status { get; set; }

}

Объявим в классе Program статический массив объектов этого класса.

static Person[] personList =

{

new Person{Name = "Paul", Birth = DateTime.Now.AddYears(-15), Status = 1 },

new Person{Name = "Alex", Birth = DateTime.Now.AddYears(-45), Status = 17 },

new Person{Name = "Peter", Birth = DateTime.Now.AddYears(-50), Status = 21 },

new Person{Name = "John", Birth = DateTime.Now.AddYears(-35), Status = 8 },

new Person{Name = "Zorro", Birth = DateTime.Now.AddYears(-25), Status = 8 },

new Person{Name = "Alex", Birth = DateTime.Now.AddYears(-15), Status = 12 },

new Person{Name = "Alex", Birth = DateTime.Now.AddYears(-45), Status = 12 }

};

Используем extension-метод OrderBy для упорядочивания элементов по возрастанию статуса. Для этого достаточно вызвать OrderBy для массива personList и подать на вход λ-выражение, определяющее поле ключа сортировки.

static void TestOrderBy()

{

var q = personList.OrderBy(c => c.Status);

Console.WriteLine("\nPersons ordered by Status:");

foreach (var p in q)

Console.WriteLine("{0} {1}  {2}", p.Name.PadRight(7),

p.Birth.ToShortDateString(), p.Status);

}

Для сортировки в порядке убывания надо заменить метод OrderBy на OrderByDescending. Вторые версии указанных методов имеют другую сигнатуру. Например, метод OrderBy выглядит так:

public static IOrderedEnumerable<T> OrderBy<T, TKey>(this IEnumerable<T> source,

Func<T, TKey> keySelector, IComparer<TKey> comparer);

При вызове этой версии метода следует задать два параметра: generic-делегат keySelector и адрес функции сравнения. Последняя должна быть методом класса, реализующего generic-интерфейс IComparer<T>. Для того, чтобы показать различные варианты сортировки, объявим три таких класса.

public class NameComparer : IComparer<Person>

{

public int Compare(Person p1, Person p2)

{

int n = p1.Name.CompareTo(p2.Name),

b = p1.Birth.CompareTo(p2.Birth),

s = p1.Status.CompareTo(p2.Status);

return n != 0 ? n : b != 0 ? b : s;

}

}

Назовем второй класс AgeComparer, он будет упорядочивать поля по дате рождения, затем по имени, затем по статусу. Третий класс, StatusComparer, будет упорядочивать поля по статусу, затем по имени, затем по дате рождения. Код классов вы разработаете самостоятельно. Теперь приведем код, который показывает, как использовать вторую версию метода OrderBy для сортировки массива по различным полям.