В основному це був недогляд. У 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так що вам не потрібна перевірка часу виконання в блоці нарешті, і тепер компілятор знає, що якщо ітератор є, IEnumerator<T>він може видавати безумовний виклик Dispose.
РЕДАГУВАТИ: Це неймовірно корисно для того, Disposeщоб його викликали в кінці ітерації (однак вона закінчується). Це означає, що ітератор може триматися на ресурсах - що робить можливим, наприклад, читати файл, рядок за рядком. Блоки ітератора генерують Disposeреалізації, які гарантують, що будь-які finallyблоки, що мають відношення до "поточної точки виконання" ітератора, виконуються, коли він утилізується - так що ви можете написати звичайний код в ітераторі, і очищення має відбутися належним чином.
1 Оглядаючись на специфікацію 1.0, вона вже була вказана. Я ще не зміг перевірити це попереднє твердження, що реалізація 1.0 не викликала Dispose.
IEnumerable.GetEnumerator(не-загальний) будеIDisposableтаким же?