ジェネリックIEnumerator<T>
はIDisposableから継承しますが、非ジェネリックインターフェイスIEnumeratorは継承しません。なぜこのように設計されているのですか?
通常、foreachステートメントを使用してIEnumerator<T>
インスタンスを通過します。生成されたforeachのコードには、実際には、finallyでDispose()を呼び出すtry-finallyブロックがあります。
基本的にそれは見落としでした。 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
への無条件の呼び出しを発行できます。
編集:反復の最後にDispose
が呼び出されると非常に便利です(ただし、終了します)。これは、イテレータがリソースを保持できることを意味します。これにより、たとえば、ファイルを1行ずつ読み取ることが可能になります。イテレータブロックはDispose
実装を生成し、イテレータの「現在の実行ポイント」に関連するfinally
ブロックが破棄されたときに実行されるようにします。これにより、イテレータ内で通常のコードを記述できます。クリーンアップは適切に行う必要があります。
1 1.0仕様を振り返ると、すでに指定されています。 1.0の実装がDispose
を呼び出さなかったという、この以前のステートメントをまだ確認できていません。
IEnumerable <T>はIDisposableを継承しません。ただし、IEnumerator <T>はIDisposableを継承しますが、非ジェネリックIEnumeratorは継承しません。非ジェネリックIEnumerable(IEnumeratorを返す)にforeachを使用する場合でも、コンパイラーはIDisposableのチェックを生成し、列挙子がインターフェイスを実装している場合はDispose()を呼び出します。
ジェネリックEnumerator <T>はIDisposableを継承しているので、実行時型チェックは必要ありません。Dispose()を呼び出すだけで、パフォーマンスが向上するはずです。列挙子には空のDispose()メソッドがあります。
私はこれが古い議論であることを知っていますが、ライブラリのユーザーがTのIEnumeratorを実装するだけでカスタムイテレータを実装できるT/IEnumeratorのIEnumerableを使用するライブラリを合理的に作成しました。
TのIEnumeratorがIDisposableから継承するのは非常に奇妙だと思いました。管理されていないリソースを解放したい場合は、IDisposableを実装しますか?したがって、IOストリームなどのように、実際にアンマネージリソースを保持する列挙子にのみ関連します。意味がある場合は、ユーザーにTのIEnumeratorとIDisposableの両方を列挙子に実装させないのはなぜですか?私の本では、これは単一責任の原則に違反しています-なぜ列挙子ロジックとオブジェクトの破棄を混在させるのですか?.
IEnumerable`はIDisposedを継承しますか? .NETリフレクターまたは [〜#〜] msdn [〜#〜] によると。 IEnumerator と混同していませんか? IDisposedを使用するのは、コレクションを列挙するためだけであり、寿命を意図していないためです。
AndersH自身、または彼の近くの誰かから応答を得ることができなければ、これについて決定的になるのは少し難しいです。
ただし、C#で同時に導入された「yield」キーワードに関連していると思います。 「yieldreturnx」が使用されているときにコンパイラーによって生成されたコードを見ると、IEnumeratorを実装するヘルパークラスにラップされたメソッドがあります。 IEnumeratorをIDisposableの子孫にすることで、列挙が完了したときにIEnumeratorをクリーンアップできるようになります。