С#:Где реализовать пользовательский IEnumerator<T>
-
19-09-2019 - |
Вопрос
Скажем, у меня есть класс, который реализует IEnumerable<T>
.В настоящее время он использует yield
ключевое слово в GetEnumerator()
метод.Но сейчас мне нужно сделать немного больше, например, мне хотелось бы убрать за собой.Для этого, если я ничего не упустил из виду, мне нужно реализовать IEnumerator<T>
интерфейс.Но где, по-вашему, мне следует это сделать?
Должен ли сам класс реализовать это и GetEnumerator()
возвращаться this
?Или было бы лучше спрятать это в частном классе?Или, может быть, это должен быть совершенно другой класс?Каковы некоторые распространенные практики в этом отношении?
Решение
Если все, что вам нужно сделать, это очистить некоторые ресурсы при удалении перечислителя, например, в конце foreach
цикл, то вы можете сделать это с тем, что у вас есть, просто добавьте блок try/finally в свой метод итератора.
Так:
public IEnumerator<T> GetEnumerator()
{
try
{
// your iterator code here
}
finally
{
// cleanup code here
}
}
Вот и все.
Другие советы
Я бы выбрал класс для IEnumerator<T>.При этом потребуется хранить состояние (текущую позицию), которое не является частью коллекции, а скорее частью процесса перечисления.
Возможно, вам вообще не понадобится писать класс для этого.Метод итератора может возвращать IEnumerable<T>
, поэтому, если вашему классу нужно реализовать только IEnumerable<T>
и ничего больше, просто напишите для всего этого метод-итератор.
Если нет, вам придется придерживаться внешнего класса, который реализует IEnumerable<T>
имея метод итератора для выполнения GetEnumerator
, то вам не придется делать ничего очень сложного для очистки после итерации.
IEnumerator<T>
происходит от IDisposable
.Метод итератора реализует Dispose
путем выполнения finally
блоки или любой код после последнего yield return
.