Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

static void GetOverstock(ProductInfo[] products)

{

Console.WriteLine("The overstock items!");

// Получить только товары со складским запасом более 25 единиц.

var overstock =

from p

in products

where p.NumberInStock > 25

select p;

foreach (ProductInfo c in overstock)

{

Console.WriteLine(c.ToString);

}

}

Как

демонстрировалось ранее в главе, при указании конструкции
where
разрешено применять любые операции C# для построения сложных выражений. Например, вспомните запрос, который извлекал только автомобили марки BMW, движущиеся со скоростью минимум 90 миль в час:

// Получить автомобили BMW, движущиеся со скоростью минимум 90 миль в час.

var onlyFastBMWs =

from c

in myCars

where c.Make == "BMW" && c.Speed >= 100

select c;

Проецирование в новые типы данных

Новые формы данных также можно проецировать из существующего источника данных. Давайте предположим, что необходимо принять входной параметр

ProductInfo[]
и получить результирующий набор, который учитывает только имя и описание каждого товара. Для этого понадобится определить оператор
select
, динамически выдающий новый анонимный тип:

static void GetNamesAndDescriptions(ProductInfo[] products)

{

Console.WriteLine("Names and Descriptions:");

var nameDesc =

from p

in products

select new { p.Name, p.Description };

foreach (var item in nameDesc)

{

// Можно было бы также использовать свойства Name

// и Description напрямую.

Console.WriteLine(item.ToString);

}

}

Не забывайте, что когда запрос LINQ использует проекцию, нет никакого способа узнать лежащий в ее основе тип данных, т.к. он определяется на этапе компиляции. В подобных случаях ключевое слово

var
является обязательным. Кроме того, вспомните о невозможности создания методов с неявно типизированными возвращаемыми значениями. Таким образом, следующий метод не скомпилируется:

static var GetProjectedSubset(ProductInfo[] products)

{

var nameDesc =

from p in products select new { p.Name, p.Description };

return nameDesc; // Так поступать нельзя!

}

В случае необходимости возвращения спроецированных данных вызывающему коду один из подходов предусматривает трансформацию результата запроса в объект

System.Array
с применением расширяющего метода
ТоArray
. Следовательно, модифицировав выражение запроса, как показано ниже:

// Теперь возвращаемым значением является объект Array.

static Array GetProjectedSubset(ProductInfo[] products)

{

var nameDesc =

from p in products select new { p.Name, p.Description };

// Отобразить набор анонимных объектов на объект Array.

return nameDesc.ToArray;

}

метод

GetProjectedSubset
можно вызвать и обработать возвращенные им данные:

Array objs = GetProjectedSubset(itemsInStock);

foreach (object o in objs)

{

Console.WriteLine(o); // Вызывает метод ToString

// на каждом анонимном объекте.

}

Как видите, здесь должен использоваться буквальный объект

System.Array
, а применять синтаксис объявления массива C# невозможно, учитывая, что лежащий в основе проекции тип неизвестен, поскольку речь идет об анонимном классе, который сгенерирован компилятором. Кроме того, параметр типа для обобщенного метода
ToArray<Т>
не указывается, потому что он тоже не известен вплоть до этапа компиляции.

Очевидная проблема связана с утратой строгой типизации, т.к. каждый элемент в объекте

Array
считается относящимся к типу
Object
. Тем не менее, когда нужно возвратить результирующий набор LINQ, который является результатом операции проецирования в анонимный тип, трансформация данных в тип
Array
(или другой подходящий контейнер через другие члены типа
Enumerable
) обязательна.

Проецирование в другие типы данных

В дополнение к проецированию в анонимные типы результаты запроса LINQ можно проецировать в другой конкретный тип, что позволяет применять статическую типизацию и реализацию

IEnumerable<T>
как результирующий набор. Для начала создайте уменьшенную версию класса
ProductInfo
:

namespace FunWithLinqExpressions

{

class ProductInfoSmall

{

public string Name {get; set;} = "";

public string Description {get; set;} = "";

public override string ToString

=> $"Name={Name}, Description={Description}";

}

}

Следующее изменение касается проецирования результатов запроса в коллекцию объектов

ProductInfoSmall
, а не анонимных типов. Добавьте в класс
ProductInfoSmall
следующий метод:

static void GetNamesAndDescriptionsTyped(

Поделиться с друзьями: