IEnumerator<T>
ジェネリックは IDisposable を継承していますが、非ジェネリック インターフェイス IEnumerator は継承していないことに気付きました。なぜこのように設計されているのですか?
通常、foreach ステートメントを使用してIEnumerator<T>
インスタンスを処理します。foreach の生成コードには、実際には、最終的に Dispose() を呼び出す try-finally ブロックがあります。
IEnumerator<T>
ジェネリックは IDisposable を継承していますが、非ジェネリック インターフェイス IEnumerator は継承していないことに気付きました。なぜこのように設計されているのですか?
通常、foreach ステートメントを使用してIEnumerator<T>
インスタンスを処理します。foreach の生成コードには、実際には、最終的に Dispose() を呼び出す try-finally ブロックがあります。
基本的に見落としでした。C# 1.0 では、1は呼び出されforeach
ませんでした。C# 1.2 (VS2003 で導入 - 奇妙なことに 1.1 はありません) では、反復子が実装されているかどうかをブロックでチェックインし始めました。最初にイテレータを破棄することが有用であることがわかっていれば、を拡張していたと確信しています。Dispose
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 of T
のIEnumerator of T
ユーザーが実装する必要があるカスタムイテレータを実装できるライブラリを合理的に作成しIEnumerator of T
ました。
T の IEnumerator が IDisposable から継承されるのは非常に奇妙だと思いました。管理されていないリソースを解放したい場合は、 IDisposable を実装しますか? したがって、IOストリームなど、実際に管理されていないリソースを保持する列挙子にのみ関連します。意味がある場合、TのIEnumeratorとIDisposableの両方を列挙子に実装できるようにしないのはなぜですか? 私の本では、これは単一責任の原則に違反しています - なぜ列挙子ロジックと破棄オブジェクトを混在させるのですか。
IEnumerable<T> は IDisposable を継承しません。ただし、IEnumerator<T> は IDisposable を継承しますが、非ジェネリック IEnumerator は継承しません。非ジェネリック IEnumerable (IEnumerator を返す) に対してforeachを使用する場合でも、列挙子がインターフェイスを実装している場合、コンパイラは IDisposable のチェックを生成し、Dispose() を呼び出します。
一般的な Enumerator<T> は IDisposable を継承していると思いますので、実行時の型チェックは必要ありません。列挙子には空の Dispose() メソッドがあります。
AndersH自身または彼に近い誰かから応答を得られない限り、これについて決定的なことをするのは少し難しい.
しかし、私の推測では、C# で同時に導入された「yield」キーワードに関連していると思います。「yield return x」が使用されたときにコンパイラによって生成されたコードを見ると、メソッドが IEnumerator を実装するヘルパー クラスにラップされていることがわかります。IEnumerator を IDisposable から派生させると、列挙が完了したときに確実にクリーンアップできます。
IEnumerable` は IDisposing を継承しますか? .NET リフレクターまたはMSDNによると。IEnumeratorと混同していませんか? コレクションを列挙するためだけであり、長寿のためのものではないため、IDisposing を使用します。
IIRCIEnumerable<T>
とを持つことについてのすべては、 .Net のテンプレートのものを前IEnumerable
にした結果です。IEnumerable
あなたの質問も同じだと思います。