Почему IEnumerator <T> наследовать от IDisposable, в то время как неуниверсальный IEnumerator этого не делает?

Я заметил, что универсальный IEnumerator<T> наследуется от IDisposable, а неуниверсальный интерфейс IEnumerator - нет. Почему он разработан таким образом?

Обычно мы используем оператор foreach для прохождения экземпляра IEnumerator<T>. Сгенерированный код foreach фактически имеет блок try-finally, который вызывает Dispose () в finally.

67 голосов | спросил Morgan Cheng 24 +04002008-10-24T09:27:34+04:00312008bEurope/MoscowFri, 24 Oct 2008 09:27:34 +0400 2008, 09:27:34

6 ответов


0

В основном это был недосмотр. В C # 1.0 foreach never называется 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

РЕДАКТИРОВАТЬ: невероятно полезно вызывать Dispose в конце итерации (как бы она ни заканчивалась). Это означает, что итератор может удерживать ресурсы - что делает возможным, например, чтение файла построчно. Генератор блоков итераторов Dispose реализации, которые гарантируют, что любые finally


1 Оглядываясь назад на спецификации 1.0, она уже была указана. Я еще не смог проверить это более раннее утверждение, что реализация 1.0 не вызывала Dispose.

ответил Jon Skeet 24 +04002008-10-24T10:06:29+04:00312008bEurope/MoscowFri, 24 Oct 2008 10:06:29 +0400 2008, 10:06:29
0

IEnumerable & л; Т > не наследует IDisposable. IEnumerator & л; Т > однако наследует IDisposable, а неуниверсальный IEnumerator - нет. Даже когда вы используете foreach для неуниверсального IEnumerable (который возвращает IEnumerator), компилятор все равно сгенерирует проверку для IDisposable и вызовет Dispose (), если перечислитель реализует интерфейс.

Полагаю, общий Enumerator <T> наследуется от IDisposable, поэтому нет необходимости проверять тип во время выполнения - он может просто пойти дальше и вызвать Dispose (), который должен иметь лучшую производительность, поскольку его, вероятно, можно оптимизировать, если у перечислителя есть пустой метод Dispose () .

ответил Mark Cidade 24 +04002008-10-24T09:56:13+04:00312008bEurope/MoscowFri, 24 Oct 2008 09:56:13 +0400 2008, 09:56:13
0

Я знаю, что это старая дискуссия, но я заново написал библиотеку, в которой я использовал IEnumerable из T /IEnumerator из T, где пользователи библиотеки могли реализовывать пользовательские итераторы, им просто нужно было реализовать IEnumerator из T.

Мне показалось очень странным, что IEnumerator из T наследовал бы от IDisposable. Мы реализуем IDisposable, если мы хотим освободить неуправляемые ресурсы, верно? Таким образом, это будет актуально только для перечислителей, которые на самом деле содержат неуправляемые ресурсы - например, поток ввода-вывода и т. Д. Почему бы просто не позволить пользователям реализовать IEnumerator из T и IDisposable на своем перечислителе, если это имеет смысл? В моей книге это нарушает принцип единственной ответственности - зачем смешивать счетную логику и уничтожать объекты.

ответил JAXN 28 WedEurope/Moscow2011-12-28T10:42:41+04:00Europe/Moscow12bEurope/MoscowWed, 28 Dec 2011 10:42:41 +0400 2011, 10:42:41
0

IEnumerable` наследует IDisposing? Согласно отражателю .NET или MSDN . Вы уверены, что не путаете это с IEnumerator ? При этом используется IDisposing, потому что он предназначен только для перечисления коллекции и не предназначен для долговечности.

ответил Aaron Powell 24 +04002008-10-24T09:45:45+04:00312008bEurope/MoscowFri, 24 Oct 2008 09:45:45 +0400 2008, 09:45:45
0

Немного трудно определиться с этим, если только вам не удастся получить ответ от самого AndersH или кого-то из его близких.

Однако я предполагаю, что оно относится к ключевому слову yield, которое было введено в C # одновременно. Если вы посмотрите на код, сгенерированный компилятором при использовании «yield return x», то увидите, что метод обернут в класс помощника, который реализует IEnumerator; IEnumerator, происходящий из IDisposable, гарантирует, что он может очиститься после завершения перечисления.

ответил Bevan 24 +04002008-10-24T09:57:36+04:00312008bEurope/MoscowFri, 24 Oct 2008 09:57:36 +0400 2008, 09:57:36
0

IIRC Все дело в том, чтобы IEnumerable<T> и IEnumerable является результатом IEnumerable, предшествовавшего шаблону .Net. Я подозреваю, что ваш вопрос такой же.

ответил BCS 24 +04002008-10-24T09:29:38+04:00312008bEurope/MoscowFri, 24 Oct 2008 09:29:38 +0400 2008, 09:29:38

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132