Для типа требуется только открытый / нестатический / неуниверсальный / беспараметрический метод с именем GetEnumerator
, который должен возвращать то, что имеет открытый метод MoveNext
и открытое свойство Current
. Когда я вспоминаю г-на Эрика Липперта где-то, это было разработано так, чтобы учесть предварительную эпоху как для проблем безопасности типов, так и для проблем, связанных с боксом, в случае типов значений.
Например, это работает:
class Test
{
public SomethingEnumerator GetEnumerator()
{
}
}
class SomethingEnumerator
{
public Something Current //could return anything
{
get { }
}
public bool MoveNext()
{
}
}
//now you can call
foreach (Something thing in new Test()) //type safe
{
}
Это затем переводится компилятором в:
var enumerator = new Test().GetEnumerator();
try {
Something element; //pre C# 5
while (enumerator.MoveNext()) {
Something element; //post C# 5
element = (Something)enumerator.Current; //the cast!
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
Из раздела 8.8.4 спецификации.
Что-то, на что стоит обратить внимание, - это задействованный приоритет перечислителя - это похоже на то, что если у вас есть метод public GetEnumerator
, то это выбор по умолчанию foreach
независимо от того, кто его реализует. Например:
class Test : IEnumerable<int>
{
public SomethingEnumerator GetEnumerator()
{
//this one is called
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
}
}
( Если у вас нет публичной реализации (т. Е. Только явной реализации), тогда приоритет имеет вид IEnumerator<T>
> IEnumerator
. )