from c in colors where c.Contains("Red") select c;
return theRedColors;
}
Результат выглядит вполне ожидаемо:
Light Red
Dark Red
Red
Возвращение результатов LINQ посредством немедленного выполнения
Рассмотренный пример работает ожидаемым образом только потому, что возвращаемое значение
GetStringSubset
и запрос LINQ внутри этого метода были строго типизированными. Если применить ключевое слово
var
для определения переменной
subset
, то возвращать значение будет разрешено, только если метод по-прежнему прототипирован с возвращаемым типом
IEnumerable<string>
(и если неявно типизированная локальная переменная на самом деле совместима с указанным возвращаемым типом).
Поскольку оперировать с типом
IEnumerable<T>
несколько неудобно, можно задействовать немедленное выполнение. Скажем, вместо возвращения
IEnumerable<string>
можно было бы возвратить просто
string[]
при условии трансформации последовательности в строго типизированный массив. Именно такое действие выполняет новый метод класса
Program
:
static string[] GetStringSubsetAsArray
{
string[] colors = {"Light Red", "Green",
"Yellow", "Dark Red", "Red", "Purple"};
var theRedColors = from c in colors where c.Contains("Red") select c;
// Отобразить результаты в массив.
return theRedColors.ToArray;
}
В таком случае вызывающий код совершенно не знает, что полученный им результат поступил от запроса LINQ, и просто работает с массивом строк вполне ожидаемым образом. Вот пример:
foreach (string item in GetStringSubsetAsArray)
{
Console.WriteLine(item);
}
Немедленное выполнение также важно при попытке возвратить вызывающему коду результаты проецирования LINQ. Мы исследуем эту тему чуть позже в главе. А сейчас давайте посмотрим, как применять запросы LINQ к обобщенным и
необобщенным объектам коллекций.
Применение запросов LINQ к объектам коллекций
Помимо извлечения результатов из простого массива данных выражения запросов LINQ могут также манипулировать данными внутри классов из пространства имен
System.Collections.Generic
, таких как
List<T>
. Создайте новый проект консольного приложения по имени
ListOverCollections
и определите базовый класс
Car
, который поддерживает текущую скорость, цвет, производителя и дружественное имя:
namespace LinqOverCollections
{
class Car
{
public string PetName {get; set;} = "";
public string Color {get; set;} = "";
public int Speed {get; set;}
public string Make {get; set;} = "";
}
}
Теперь определите внутри операторов верхнего уровня локальную переменную типа
List<T>
для хранения элементов типа
Car
и с помощью синтаксиса инициализации объектов заполните список несколькими новыми объектами
Car
:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using LinqOverCollections;
Console.WriteLine("***** LINQ over Generic Collections *****\n");
// Создать список List<> объектов Car.
List<Car> myCars = new List<Car> {
new Car{ PetName = "Henry", Color = "Silver", Speed = 100, Make = "BMW"},
new Car{ PetName = "Daisy", Color = "Tan", Speed = 90, Make = "BMW"},
new Car{ PetName = "Mary", Color = "Black", Speed = 55, Make = "VW"},
new Car{ PetName = "Clunker", Color = "Rust", Speed = 5, Make = "Yugo"},
new Car{ PetName = "Melvin", Color = "White", Speed = 43, Make = "Ford"}
};
Console.ReadLine;
Доступ к содержащимся в контейнере подобъектам
Применение запроса LINQ к обобщенному контейнеру ничем не отличается от такого же действия в отношении простого массива, потому что LINQ to Objects может использоваться с любым типом, реализующим интерфейс
IEnumerable<T>
. На этот раз цель заключается в построении выражения запроса для выборки из списка
myCars
только тех объектов
Car
, у которых значение скорости больше
55
.
После получения подмножества на консоль будет выведено имя каждого объекта
Car
за счет обращения к его свойству
PetName
. Предположим, что определен следующий вспомогательный метод (принимающий параметр
List<Car>
), который вызывается в операторах верхнего уровня: