В основном это был недосмотр. В C # 1.0 foreach
никогда называется Dispose
1 . С C # 1.2 (представлен в VS2003 - странно нет 1.1) foreach
начал проверять в блоке finally
, реализован ли итератор IDisposable
- они должны были сделать это таким образом, потому что ретроспективно делая IEnumerator
Если расширение IDisposable
нарушило бы реализацию IEnumerator
. Если бы они выяснили, что для foreach
в первую очередь полезно избавиться от итераторов, я уверен, что IEnumerator
расширил бы IDisposable
.
Однако, когда вышли C # 2.0 и .NET 2.0, у них появилась новая возможность - новый интерфейс, новое наследование. Гораздо разумнее иметь расширение интерфейса IDisposable
, чтобы вам не требовалась проверка времени выполнения в блоке finally, и теперь компилятор знает, что, если итератор IEnumerator<T>
, он может генерировать безусловный вызов до Dispose
.
EDIT: невероятно полезно вызывать Dispose
в конце итерации (как бы она ни заканчивалась). Это означает, что итератор может удерживать ресурсы - что делает возможным, скажем, чтение файла построчно. Блоки итератора генерируют реализации Dispose
, которые гарантируют, что любые блоки finally
, относящиеся к «текущей точке выполнения» итератора, выполняются, когда он располагается, так что вы можете написать нормальный код внутри итератора, и очистка должна происходить соответствующим образом .
1 Возвращаясь к спецификации 1.0, она уже была указана. Я еще не смог проверить это более раннее утверждение, что реализация 1.0 не вызывала Dispose
.