Шрифт:
Интервал:
Закладка:
{
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.
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})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 следующий метод:
- Понимание SQL - Мартин Грубер - Базы данных