Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 167 168 169 170 171 172 173 174 175 ... 407
ключевое слово var. Вспомните из главы 3, что неявно типизированные переменные не могут применяться для определения параметров, возвращаемых значений, а также полей класса или структуры.

Итак, вполне вероятно, вас интересует, каким образом возвратить результат запроса внешнему коду. Ответ: в зависимости от обстоятельств. Если у вас есть результирующий набор, состоящий из строго типизированных данных, такой как массив строк или список List<T> объектов Car, тогда вы могли бы отказаться от использования ключевого слова var и указать подходящий тип IEnumerable<T> либо IEnumerable (т.к. IEnumerable<T> расширяет IEnumerable). Ниже приведен пример класса Program в новом проекте консольного приложения по имени LinqRetValues:

using System;

using System.Collections.Generic;

using System.Linq;

Console.WriteLine("***** LINQ Return Values *****n");

IEnumerable<string> subset = GetStringSubset();

foreach (string item in subset)

{

  Console.WriteLine(item);

}

Console.ReadLine();

static IEnumerable<string> GetStringSubset()

{

  string[] colors = {"Light Red", "Green", "Yellow", "Dark Red", "Red", "Purple"};

  // Обратите внимание, что subset является

  // совместимым с IEnumerable<string> объектом.

  IEnumerable<string> theRedColors =

     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>), который вызывается в операторах верхнего уровня:

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

1 ... 167 168 169 170 171 172 173 174 175 ... 407
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен бесплатно.

Оставить комментарий