Литмир - Электронная Библиотека
A
A

using System.Collections;

namespace CustomEnumerator

{

  // Garage содержит набор объектов Car.

  public class Garage

  {

    private Car[] carArray = new Car[4];

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

    public Garage()

    {

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

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

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

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

    }

  }

}

В идеальном случае было бы удобно проходить по внутренним элементам объекта

Garage
с применением конструкции
foreach
как в ситуации с массивом значений данных:

using System;

using CustomEnumerator;

// Код выглядит корректным...

Console.WriteLine("***** Fun with IEnumerable / IEnumerator *****\n");

Garage carLot = new Garage();

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

foreach (Car c in carLot)

{

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

    c.PetName, c.CurrentSpeed);

}

Console.ReadLine();

К сожалению, компилятор информирует о том, что в классе Garage не реализован метод по имени

GetEnumerator()
, который формально определен в интерфейсе
IEnumerable
, находящемся в пространстве имен
System.Collections
.

На заметку! В главе 10 вы узнаете о роли обобщений и о пространстве имен

System.Collections.Generic
. Как будет показано, это пространство имен содержит обобщенные версии интерфейсов
IEnumerable/IEnumerator
, которые предлагают более безопасный к типам способ итерации по элементам.

Классы или структуры, которые поддерживают такое поведение, позиционируются как способные предоставлять вызывающему коду доступ к элементам, содержащимся внутри них (в рассматриваемом примере самому ключевому слову

foreach
). Вот определение этого стандартного интерфейса:

// Данный интерфейс информирует вызывающий код о том,

// что элементы объекта могут перечисляться

public interface IEnumerable

{

   IEnumerator GetEnumerator();

}

Как видите, метод

GetEnumerator()
возвращает ссылку на еще один интерфейс по имени
System.Collections.IEnumerator
, обеспечивающий инфраструктуру, которая позволяет вызывающему коду обходить внутренние объекты, содержащиеся в совместимом с
IEnumerable
контейнере:

// Этот интерфейс позволяет вызывающему коду получать элементы контейнера.

public interface IEnumerator

{

   bool MoveNext ();   // Переместить вперед внутреннюю позицию курсора.

   object Current { get;}  // Получить текущий элемент

                           // (свойство только для чтения).

   void Reset (); // Сбросить курсор в позицию перед первым элементом.

}

Если вы хотите обновить тип

Garage
для поддержки этих интерфейсов, то можете пойти длинным путем и реализовать каждый метод вручную. Хотя вы определенно вольны предоставить специализированные версии методов
GetEnumerator()
,
MoveNext()
,
Current
и
Reset()
, существует более легкий путь. Поскольку тип
System.Array
(а также многие другие классы коллекций) уже реализует интерфейсы
IEnumerable
и
IEnumerator
, вы можете просто делегировать запрос к
System.Array
следующим образом (обратите внимание, что в файл кода понадобится импортировать пространство имен
System.Collections
):

using System.Collections;

...

public class Garage : IEnumerable

{

  // System.Array уже реализует IEnumerator!

  private Car[] carArray = new Car[4];

  public Garage()

  {

    carArray[0] = new Car("FeeFee", 200);

    carArray[1] = new Car("Clunker", 90);

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

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

  }

 // Возвратить IEnumerator объекта массива.

  public IEnumerator GetEnumerator()

    => carArray.GetEnumerator();

}

После такого изменения тип

Garage
можно безопасно использовать внутри конструкции
foreach
. Более того, учитывая, что метод
GetEnumerator()
был определен как открытый, пользователь объекта может также взаимодействовать с типом
IEnumerator
:

175
{"b":"847442","o":1}