Почему метод Reset() в классе Enumerator должен вызывать NotSupportedException()?

Из того, что я видел на http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx, и статьи Джона Скита, сама спецификация С# говорит об этом. В чем причина?

Ответ 1

Это не то, как я прочитал С# spec [Word doc]. Раздел 10.14.4 "Объекты перечислителя":

... [E] объекты числителя не поддерживают метод IEnumerator.Reset. Вызов этого метода вызывает исключение System.NotSupportedException.

Однако этот раздел (и оператор) специфичен для "объектов перечислителя", который определяется как:

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

Другими словами, "объект перечислителя" является компилятором, сгенерированным IEnumerator 1. Нет ограничений для каждого IEnumerator, только те, которые генерируются из блоков итератора (aka yield).

Почему? Я подозреваю, потому что это невозможно сделать в общем случае - без сохранения каждой ценности и связанных с этим ограничений памяти. Объедините это с тем, что IEnumerator.Reset() редко используется (когда последний раз, когда вы Reset перечислитель?) И что MSDN специально призывает, что ему нужно не будут реализованы:

Метод Reset предоставляется для совместимости COM. Это необязательно должно быть реализовано; вместо этого разработчик может просто выбросить исключение NotSupportedException.

и вы можете вырезать много сложностей, и никто не замечает этого.

Как и требовать, чтобы он выбрал 2 я предполагаю, что это просто проще, чем позволить разработчику решить. IMO, это немного требует запроса - могут быть разумные случаи, когда компилятор (или другая реализация 1) может генерировать метод Reset, но я не вижу его как реальная проблема.

1 Технически спецификация оставляет возможность других реализаций:

Объект перечислителя обычно является экземпляром класса перечислителя, сгенерированного компилятором, который инкапсулирует код в блок итератора и реализует интерфейсы перечислителя, но возможны другие методы реализации.

но я не знаю других конкретных реализаций. Независимо от того, чтобы быть совместимым, другим реализациям "объекта-перечислителя" пришлось бы также метать NotSupportedException.

2 Nitpicker corner: Я думаю, что может быть какое-то придирчиво даже в "требовании" бросить. Спектр, не используя предпочтительный "ДОЛЖЕН, ДОЛЖЕН, МОЖЕТ" формулировать, оставляет его немного открытым. Я читаю "причины" больше как примечание о реализации - не требование. Опять же, я не читал всю спецификацию, поэтому, возможно, они определяют эти термины немного больше или более явны в другом месте.

Ответ 2

Невозможно правильно поддерживать во всех последовательностях; многие только один раз (сетевые потоки и т.д.). И если вы не можете полагаться на это все на время, это бесполезно, поскольку абстракция нарушена. Конечно, у вас может быть IResettableEnumerator, но Reset() on IEnumerator не работает  Работа. Честно говоря, это была ошибка (ИМО).

Я подозреваю, что это сделало бы итераторы более сложными даже более сложными (они в настоящее время являются одной из двух наиболее сложных частей компилятора, я не помню, что такое "верх", или анонимные методы/захваченные переменные).

Ответ 3

Вот что говорит MSDN

Метод Reset предоставляется для COM совместимость. Он не обязательно требуется; вместо этого исполнитель может просто бросить исключение NotSupportedException.

http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx > MSDN IEnumerator..::. Метод сброса

Он не говорит, что должен, он просто говорит, что может.

EDIT: Однако, как отметил Марк, в С# 2.0 Spec есть разница

22.2 Объекты перечислителя

Обратите внимание, что объекты перечислителя не поддерживают метод IEnumerator.Reset. Вызов этого метода вызываетИсправление System.NotSupportedException выброшены.