Сделать класс 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
массив с помощью конструкции из-за реализации этих двух интерфейсов.
Чтобы создать проект консольного приложения в Visual C#, выполните следующие действия:
- Запустите Microsoft Visual Studio .NET или Visual Studio.
- В меню Файл выберите пункт Создать и затем пункт Проект.
- Нажмите Проекты Visual C# в разделе Типы проектов, а затем нажмите Консольное приложение в разделе Шаблоны.
- В поле Имя введите ConsoleEnum.
Переименуйте 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(); } } }
В меню Проект щелкните Добавить класс и введите car в поле Имя .
Замените код в 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
В меню Проект щелкните Добавить класс , чтобы добавить в проект другой класс, а затем введите cars в поле Имя .
Замените код в 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];} } } }
Запустите проект.
В окне консоли отображаются следующие выходные данные:
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);
}
}
}
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по