new { Artist="Frank Sinatra", Date=new DateTime(1957,4,12), Song="It started all over again" },
new { Artist="Nat King Cole", Date=new DateTime(1956,11,29), Song="Impossible" },
new { Artist="Dinah Washington", Date=new DateTime(1975,9,21), Song="Call Me Irresponsible" },
new { Artist="Peggy Lee", Date=new DateTime(1978,5,9), Song="As Time Goes By" }
};
var q = songs
.Select(s => new { len = s.Song.Length, s.Song, s.Artist, s.Date })
.Where(s => s.Date > DateTime.Now.AddYears(-60) )
.OrderBy(s => s.len)
.Select(s => new { s.Song, Date = s.Date, s.len });
int k = 0;
foreach (var s in q)
Console.WriteLine("{0}. {1}, {2,-2}, {3}", ++k, s.Date.ToShortDateString(), s.len, s.Song);
Отметим, что компилятор распознает контекстное ключевое слово yield только если после него следует оператор return или break. Конструкция yield return, помещенная в итерационный блок, заставляет перечислимый класс работать в рамках следующего в цепочке перечислимого класса. Распросраняясь по цепочке, это правило осуществляет задержку выполнения всей последовательности вызовов расширяющих методов.
Любопытно, что если изменить первый из двух запросов, рассмотренных ранее (в разделе "Фильтрация данных"), и добавить в него вызов метода ToArray()
string[] oo = words.Where(c => c.Contains("oo")).ToArray();
то метод Where выполнится сразу, без задержки. То же самое произойдет с любым другим отложенным запросом. Методы ToArray() и ToArray<T>() также являются расширениями IEnumerable<T>. Они преобразуют ленивую последовательность в массив. Отметьте, что следующий код эквивалентен предыдущему.
string[] oo = words.Where(c => c.Contains("oo")).ToArray<string>();
Вместо массива вы можете преобразовать выходную последовательность в generic-список. Для этого надо воспользоваться extension-методом ToList() или ToList<string>().
List<string> ooList = words.Where(c => c.Contains("oo")).ToList();
Рассмотрим, как работают методы Select и SelectMany, которые позволяют проецировать данные на удобные нам структуры. Тип элементов выходной последовательности может отличаться от типа данных входной. Методы Select и SelectMany требуют в качестве параметра задать адрес трансформирующей функции. Она называется селектором (selector) и должна создавать одно значение для каждого значения перебираемой последовательности.
Запомните. Метод Where требует задать предикат, а методы Select и SelectMany требуют задать селектор.
Если селектор возвращает значение, которое, в свою очередь, является последовательностью, то нам необходимо написать код прохода по ней. В случае использования SelectMany этого делать не надо, так как сам метод SelectMany обрабатывает последовательность возвращаемых последовательностей. Он сливает их в одну общую последовательность. Рассмотрим пример, который иллюстрирует использование обоих методов для вывода результатов экзаменов для массива студентов. Пусть каждый студент задан объектом класса Stud с таким набором автогенерируемых свойств.
class Stud
{
public string Name { get; set; }
public int[] Marks { get; set; }
}
Массив студентов можно задать таким образом.
Stud[] studs =
{
new Stud { Name="John Best", Marks = new[]{ 5, 5, 5, 5, 5 } },
new Stud { Name="Joy Amore", Marks = new[]{ 4, 4, 3, 4 } },
new Stud { Name="Jim Lowson", Marks = new[]{ 3, 3, 2 } },
};
Далее мы создаем отложенный запрос с помощью метода Select.
var q = studs.Select (s => s.Marks); // Тип переменной q - IEnumerable<int[]>
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.