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

ЖАНРЫ

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

myInts.PrintDataAndBeep;

Console.ReadLine;

На этом исследование расширяющих методов C# завершено. Помните, что данное языковое средство полезно, когда необходимо расширить функциональность типа, но вы не хотите создавать подклассы (или не можете, если тип запечатан) в целях обеспечения полиморфизма. Как вы увидите позже, расширяющие методы играют ключевую роль в API-интерфейсах LINQ. На самом деле вы узнаете, что в API-интерфейсах LINQ одним из самых часто расширяемых элементов является класс или структура, реализующая обобщенную версию интерфейса

IEnumerable
.

Поддержка

расширяющего метода GetEnumerator (нововведение в версии 9.0)

До выхода версии C# 9.0 для применения оператора

foreach
с экземплярами класса в этом классе нужно было напрямую определять метод
GetEnumerator
. Начиная с версии C# 9.0, оператор
foreach
исследует расширяющие методы класса и в случае, если обнаруживает метод
GetEnumerator
, то использует его для получения реализации
IEnumerator
, относящейся к данному классу. Чтобы удостовериться в сказанном, добавьте новый проект консольного приложения по имени
ForEachWithExtensionMethods
и поместите в него упрощенные версии классов
Car
и
Garage
из главы 8:

// Car.cs

using System;

namespace ForEachWithExtensionMethods

{

class Car

{

// Свойства класса Car.

public int CurrentSpeed {get; set;} = 0;

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

// Конструкторы.

public Car {}

public Car(string name, int speed)

{

CurrentSpeed = speed;

PetName = name;

}

// Выяснить, не перегрелся ли двигатель Car.

}

}

// Garage.cs

namespace ForEachWithExtensionMethods

{

class Garage

{

public Car[] CarsInGarage { get; set; }

// При запуске заполнить несколькими объектами Car.

public Garage

{

CarsInGarage = new Car[4];

CarsInGarage[0] = new Car("Rusty", 30);

CarsInGarage[1] = new Car("Clunker", 55);

CarsInGarage[2] = new Car("Zippy", 30);

CarsInGarage[3] = new Car("Fred", 30);

}

}

}

Обратите внимание, что класс

Garage
не реализует интерфейс
IEnumerable
и не имеет метода
GetEnumerator
.
Метод
GetEnumerator
добавляется через показанный ниже класс
GarageExtensions
:

namespace ForEachWithExtensionMethods

{

static class GarageExtensions

{

public static IEnumerator GetEnumerator(this Garage g)

=> g.CarsInGarage.GetEnumerator;

}

}

Код для тестирования этого нового средства будет таким же, как код, который применялся для тестирования метода

GetEnumerator
в главе 8. Модифицируйте файл
Program.cs
следующим образом:

using System;

using ForEachWithExtensionMethods;

Console.WriteLine("***** Support for Extension Method GetEnumerator *****\n");

Garage carLot = new Garage;

// Проход по всем объектам Car в коллекции?

foreach (Car c in carLot)

{

Console.WriteLine("{0} is going {1} MPH",

c.PetName, c.CurrentSpeed);

}

Вы увидите, что код работает, успешно выводя на консоль список объектов автомобилей и скоростей их движения:

***** Support for Extension Method GetEnumerator *****

Rusty is going 30 MPH

Clunker is going 55 MPH

Zippy is going 30 MPH

Fred is going 30 MPH

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

foreach
могут использоваться даже те классы, которые для этого не предназначались.

Понятие анонимных типов

Программистам на объектно-ориентированных языках хорошо известны преимущества определения классов для представления состояния и функциональности заданного элемента, который требуется моделировать. Всякий раз, когда необходимо определить класс, предназначенный для многократного применения и предоставляющий обширную функциональность через набор методов, событий, свойств и специальных конструкторов, устоявшаяся практика предусматривает создание нового класса С#.

Тем не менее, возникают и другие ситуации, когда желательно определять класс просто в целях моделирования набора инкапсулированных (и каким-то образом связанных) элементов данных безо всяких ассоциированных методов, событий или другой специализированной функциональности. Кроме того, что если такой тип должен использоваться только небольшим набором методов внутри программы? Было бы довольно утомительно строить полное определение класса вроде показанного ниже, если хорошо известно, что класс будет применяться только в нескольких местах. Чтобы подчеркнуть данный момент, вот примерный план того, что может понадобиться делать, когда нужно создать "простой" тип данных, который следует обычной семантике на основе значений:

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