Поделиться через


Создание класса Visual C# доступным для использования в инструкции foreach

В этой статье показано, как использовать IEnumerable интерфейсы для IEnumerator создания класса, который можно использовать в инструкции foreach .

Исходная версия продукта: Visual Studio
Исходный номер базы знаний: 322022

Интерфейс IEnumerator

IEnumerable и IEnumerator часто используются вместе. Хотя эти интерфейсы похожи (и имеют аналогичные имена), они имеют разные цели.

Интерфейс IEnumerator предоставляет итеративную возможность для коллекции, которая является внутренней для класса. IEnumerator требуется реализовать три метода:

  • Метод MoveNext , который увеличивает индекс коллекции на 1 и возвращает логическое значение, указывающее, достигнут ли конец коллекции.

  • Метод Reset , который сбрасывает индекс коллекции до начального значения -1. Это делает перечисление недействительным.

  • Метод, возвращающий Current текущий объект в position.

    public bool MoveNext()
    {
        position++;
        return (position < carlist.Length);
    }
    public void Reset()
    {
        position = -1;
    }
    public object Current
    {
        get { return carlist[position];}
    }
    

Интерфейс IEnumerable

Интерфейс IEnumerable обеспечивает поддержку foreach итерации. IEnumerable требуется реализовать GetEnumerator метод.

public IEnumerator GetEnumerator()
{
    return (IEnumerator)this;
}

Когда следует использовать интерфейс

Изначально может возникнуть путаница в использовании этих интерфейсов. Интерфейс IEnumerator предоставляет итерацию по объекту типа коллекции в классе. Интерфейс IEnumerable разрешает перечисление с помощью foreach цикла. GetEnumerator Однако метод IEnumerable интерфейса возвращает IEnumerator интерфейс. Поэтому для реализации IEnumerableнеобходимо также реализовать IEnumerator. Если вы не реализуете IEnumerator, вы не можете привести возвращаемое значение из GetEnumerator метода IEnumerable интерфейса IEnumerator .

В целом, использование IEnumerable этого класса требует реализации IEnumeratorкласса. Если вы хотите предоставить поддержку foreach, реализуйте оба интерфейса.

Пошаговый пример

В следующем примере показано, как использовать эти интерфейсы. В этом примере IEnumerator интерфейсы используются IEnumerable в классе с именем cars. Класс cars имеет внутренний массив car объектов. Клиентские приложения могут перечислять этот внутренний foreach массив с помощью конструкции из-за реализации этих двух интерфейсов.

  1. Выполните следующие действия, чтобы создать проект консольного приложения в Visual C#:

    1. Запустите Microsoft Visual Studio .NET или Visual Studio.
    2. В меню Файл выберите пункт Создать и затем пункт Проект.
    3. Нажмите Проекты Visual C# в разделе Типы проектов, а затем нажмите Консольное приложение в разделе Шаблоны.
    4. В поле "Имя" введите ConsoleEnum.
  2. Переименуйте Class1.cs на host.cs, а затем замените код в host.cs следующим кодом:

    using System;
    namespace ConsoleEnum
    {
       class host
       {
           [STAThread]
           static void Main(string[] args)
           {
               cars C = new cars();
               Console.WriteLine("\nInternal Collection (Unsorted - IEnumerable,Enumerator)\n");
               foreach(car c in C)
               Console.WriteLine(c.Make + "\t\t" + c.Year);
               Console.ReadLine();
           }
       }
    }
    
  3. В меню "Проект" нажмите кнопку "Добавить класс", а затем введите автомобиль в поле "Имя".

  4. Замените код в car.cs следующим кодом:

    using System;
    using System.Collections;
    namespace ConsoleEnum
    {
       public class car
       {
           private int year;
           private string make;
           public car(string Make,int Year)
           {
               make=Make;
               year=Year;
           }
           public int Year
           {
               get  {return year;}
               set {year=value;}
           }
           public string Make
           {
               get {return make;}
               set {make=value;}
           }
       }//end class
    }//end namespace
    
  5. В меню "Проект" нажмите кнопку "Добавить класс", чтобы добавить другой класс в проект, а затем введите автомобили в поле "Имя".

  6. Замените код в cars.cs следующим кодом:

    using System;
    using System.Collections;
    namespace ConsoleEnum
    {
        public class cars : IEnumerator,IEnumerable
        {
           private car[] carlist;
           int position = -1;
           //Create internal array in constructor.
           public cars()
           {
               carlist= new car[6]
               {
                   new car("Ford",1992),
                   new car("Fiat",1988),
                   new car("Buick",1932),
                   new car("Ford",1932),
                   new car("Dodge",1999),
                   new car("Honda",1977)
               };
           }
           //IEnumerator and IEnumerable require these methods.
           public IEnumerator GetEnumerator()
           {
               return (IEnumerator)this;
           }
           //IEnumerator
           public bool MoveNext()
           {
               position++;
               return (position < carlist.Length);
           }
           //IEnumerable
           public void Reset()
           {
               position = -1;
           }
           //IEnumerable
           public object Current
           {
               get { return carlist[position];}
           }
        }
      }
    
  7. Запустите проект.

В окне консоли отображаются следующие выходные данные:

Ford            1992
Fiat            1988
Buick           1932
Ford            1932
Dodge           1999
Honda           1977

Рекомендации

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

  • Реализуйте IEnumerator вложенном классе, чтобы создать несколько перечислителей.
  • Предоставьте обработку исключений Current IEnumeratorдля метода . Если содержимое коллекции изменяется, reset вызывается метод. В результате текущий перечислитель недопустим, и вы получаете IndexOutOfRangeException исключение. Другие обстоятельства также могут вызвать это исключение. Поэтому реализуйте блок для перехвата Try...Catch этого исключения и создания InvalidOperationException исключения.
using System;
using System.Collections;
namespace ConsoleEnum
{
    public class cars : IEnumerable
    {
        private car[] carlist;
  
        //Create internal array in constructor.
        public cars()
        {
            carlist= new car[6]
            {
                new car("Ford",1992),
                new car("Fiat",1988),
                new car("Buick",1932),
                new car("Ford",1932),
                new car("Dodge",1999),
                new car("Honda",1977)
            };
        }
        //private enumerator class
        private class  MyEnumerator:IEnumerator
        {
            public car[] carlist;
            int position = -1;

            //constructor
            public MyEnumerator(car[] list)
            {
                carlist=list;
            }
            private IEnumerator getEnumerator()
            {
                return (IEnumerator)this;
            }
            //IEnumerator
            public bool MoveNext()
            {
                position++;
                return (position < carlist.Length);
            }
            //IEnumerator
            public void Reset()
            {
                position = -1;
            }
            //IEnumerator
            public object Current
            {
                get
                {
                    try
                    {
                        return carlist[position];
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
        }  //end nested class
      public IEnumerator GetEnumerator()
      {
          return new MyEnumerator(carlist);
      }
    }
}