// Найти в List<> все объекты Car, у которых значение Speed больше 55.
var fastCars = from c in myCars where c.Speed > 55 select c;
foreach (var car in fastCars)
{
Console.WriteLine("{0} is going too fast!", car.PetName);
}
}
Обратите
внимание, что выражение запроса захватывает из
List<T>
только те элементы, у которых значение
Speed
больше
55
. Запустив приложение, вы увидите, что критерию поиска отвечают только два элемента —
Нenry
и
Daisy
.
Чтобы построить более сложный запрос, можно искать только автомобили марки BMW со значением
Speed
больше
90
. Для этого нужно просто создать составной булевский оператор с применением операции
&&
языка С#:
static void GetFastBMWs(List<Car> myCars)
{
// Найти быстрые автомобили BMW!
var fastCars = from c in myCars
where c.Speed > 90 && c.Make == "BMW" select c;
foreach (var car in fastCars)
{
Console.WriteLine("{0} is going too fast!", car.PetName);
}
}
Теперь выводится только одно имя
Henry
.
Применение запросов LINQ к необобщенным коллекциям
Вспомните, что операции запросов LINQ спроектированы для работы с любым типом, реализующим интерфейс
IEnumerable<T>
(как напрямую, так и через расширяющие методы). Учитывая то, что класс
System.Array
оснащен всей необходимой инфраструктурой, может оказаться сюрпризом, что унаследованные (необобщенные) контейнеры в пространстве имен
System.Collections
такой поддержкой не обладают. К счастью, итерация по данным, содержащимся внутри необобщенных коллекций, по-прежнему возможна с использованием обобщенного расширяющего метода
Enumerable.OfТуре<Т>
.
При вызове метода
OfТуре<Т>
на объекте необобщенной коллекции (наподобие
ArrayList
) нужно просто указать тип элемента внутри контейнера, чтобы извлечь совместимый с
IEnumerable<T>
объект. Сохранить этот элемент данных в коде можно посредством неявно типизированной переменной.
Взгляните на показанный ниже новый метод, который заполняет
ArrayList
набором объектов
Car
(не забудьте импортировать пространство имен
System.Collections
в начале файла
Program.cs
):
static void LINQOverArrayList
{
Console.WriteLine("***** LINQ over ArrayList *****");
// Необобщенная коллекция объектов Car.
ArrayList myCars = new ArrayList {
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"}
};
//
Трансформировать ArrayList в тип, совместимый c IEnumerable<T>.
var myCarsEnum = myCars.OfType<Car>;
// Создать выражение запроса, нацеленное на совместимый с IEnumerable<T> тип.
var fastCars = from c in myCarsEnum where c.Speed > 55 select c;
foreach (var car in fastCars)
{
Console.WriteLine("{0} is going too fast!", car.PetName);
}
}
Аналогично предшествующим примерам этот метод, вызванный в операторах верхнего уровня, отобразит только имена
Henry
и
Daisy
, основываясь на формате запроса LINQ.
Фильтрация данных с использованием метода OfТуре<Т>
Как вы уже знаете, необобщенные типы способны содержать любые комбинации элементов, поскольку члены этих контейнеров (вроде
ArrayList
) прототипированы для приема
System.Object
. Например, предположим, что
ArrayList
содержит разные элементы, часть которых являются числовыми. Получить подмножество, состоящее только из числовых данных, можно с помощью метода
OfТуре<Т>
, т.к. во время итерации он отфильтрует элементы, тип которых отличается от заданного:
К настоящему моменту вы уже умеете применять запросы LINQ к массивам, а также обобщенным и необобщенным коллекциям. Контейнеры подобного рода содержат элементарные типы C# (целочисленные и строковые данные) и специальные классы. Следующей задачей будет изучение многочисленных дополнительных операций LINQ, которые могут использоваться для построения более сложных и полезных запросов.