なぜIEnumerator< T> IDisposableを継承しますが、非ジェネリックIEnumeratorは継承しませんか?
-
04-07-2019 - |
質問
汎用の IEnumerator< T>
はIDisposableを継承していますが、非汎用インターフェイスのIEnumeratorは継承していません。なぜこのように設計されているのですか?
通常、foreachステートメントを使用して IEnumerator< T>
インスタンスを処理します。 foreachの生成されたコードには、実際に、最終的にDispose()を呼び出すtry-finallyブロックがあります。
解決
基本的には見落としでした。 C#1.0では、 foreach
never は Dispose
1 と呼ばれていました。 C#1.2(VS2003で導入-奇妙なことに1.1はありません) foreach
は、イテレータが IDisposable
を実装しているかどうかを finally
ブロックでチェックし始めました-遡及的に IEnumerator
を IDisposable
を拡張すると、すべての IEnumerator
の実装が破損するため、彼らはそのようにしなければなりませんでした。 foreach
がイテレータを最初に廃棄することが有用であると彼らが判断した場合、 IEnumerator
は IDisposable
を拡張したはずです。 。
ただし、C#2.0と.NET 2.0が登場したとき、新しいインターフェース、新しい継承という新しい機会がありました。インターフェイスが IDisposable
を拡張するようにすると、finallyブロックで実行時チェックが不要になり、コンパイラーはイテレーターが IEnumerator&lt ; T>
は、 Dispose
の無条件呼び出しを発行できます。
EDIT: Dispose
が反復の終了時に呼び出されると、非常に便利です(ただし、終了します)。これは、イテレータがリソースを保持できることを意味します。これにより、イテレータは、たとえばファイルを1行ずつ読み取ることが可能になります。イテレータブロックは、「現在の実行ポイント」に関連する finally
ブロックを確実にする Dispose
実装を生成します。イテレータは破棄されるときに実行されます。したがって、イテレータ内に通常のコードを記述でき、クリーンアップが適切に行われます。
1 1.0仕様を振り返ると、すでに指定されています。 1.0実装が Dispose
を呼び出さなかったという以前の声明をまだ確認できていません。
他のヒント
IEnumerable< T> IDisposableを継承しません。 IEnumerator< T>ただし、IDisposableは継承しますが、非汎用IEnumeratorは継承しません。非ジェネリックIEnumerable(IEnumeratorを返す)に foreach を使用する場合でも、コンパイラはIDisposableのチェックを生成し、列挙子がインターフェイスを実装している場合はDispose()を呼び出します。
一般的な列挙子< T> IDisposableを継承するので、実行時の型チェックを行う必要はありません。先に進んで、Dispose()を呼び出すことができます。これは、列挙子に空のDispose( )メソッド。
これは古い議論ですが、ライブラリのユーザーがTのIEnumeratorを実装するだけのカスタムイテレータを実装できるTのT / IEnumeratorのIEnumerableを使用するライブラリを合理的に作成しました。
TのIEnumeratorがIDisposableを継承することは非常に奇妙であることがわかりました。管理されていないリソースを解放したい場合、IDisposableを実装しますか? IOストリームなど、アンマネージリソースを実際に保持する列挙子にのみ関係します。理にかなっている場合、列挙子にTのIEnumeratorとIDisposableの両方をユーザーに実装させないのはなぜですか。私の本では、これは単一の責任原則に違反しています-列挙子ロジックとオブジェクトの破棄を混在させる理由。
IEnumerable`はIDisposingを継承しますか? .NETリフレクターまたは MSDN によると。 IEnumerator と混同していないのですか? IDisposingは、コレクションを列挙するためだけに使用され、寿命を目的としないためです。
AndersH自身、または彼に近い人から応答を得ることができない限り、これについて明確にするのは少し難しい。
しかし、私の推測では、それは「収量」に関連していると思われます。 C#で同時に導入されたキーワード。 " yield return x"のときにコンパイラによって生成されたコードを見ると、を使用すると、IEnumeratorを実装するヘルパークラスにラップされたメソッドが表示されます。 IEnumeratorをIDisposableから派生させると、列挙が完了したときにクリーンアップできます。
IIRC IEnumerable< T>
および IEnumerable
を使用することについてのすべては、.Netのテンプレートに先行する IEnumerable
の結果です。あなたの質問も同じように思われます。