Применение запросов 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>
), который вызывается в операторах верхнего уровня:
static void GetFastCars(List<Car> myCars)
{
// Найти в 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Туре<Т>()
.