2008年08月06日

IEnumerator<T>は、IDisposableを実装してる(2)

  
NyaRuRuさんの記事「IEnumerator を実装していれば必ず IDisposable である理由」を読んだ僕なりの理解。

IEnumeratorの骨格はとこんな感じです。(かなりいいかげん)

    class EnumeratorSample<T> : IEnumerator<T> {
public int Current {
get { ... }
}

public bool MoveNext() {
...
}

public void Reset() {
...
}
}

# 僕はこのクラスを実装したことは無いですが...

もし、このクラス内で解放すべきリソースを保持しているとすると、正常系では、MoveNext内で最後まで列挙が終わったことを確認した時にリソースを解放する必要があるわけですね。
でも、それだけだと完全ではないです。
途中で列挙を終えてしまった場合は、リソースを解放するタイミングがありません。
これでは困ります。
そのため、IEnumerator は、IDisposableを実装することとして、foreachで途中でbreakされた場合などでも、Disposeメソッドが呼ばれる実装にしているということだと思います。

そういう意味では、非ジェネリックなIEnumeratorでも、同じことなので、IDisposableが実装されていれば、Disposeを呼ぶようにしないといけませんね。


この記事へのコメント
例えば以下のコードが常に正しく動くために,Dispose 呼び出しは重要ですね.

static IEnumerable<string> GetLines(string filename)
{
  using (var sr = new StreamReader(filename))
  {
    while(true)
    {
      var line = sr.ReadLine();
      if(line == null) yield break;
      yield return line;
    }
  }
}

列挙の途中で break されたときにも,Dispose でコールバックしてあげることで StreamReader は Dispose されます.
こういうコードを安心して書けるためにも,信頼の連鎖としての Dispose 呼び出しは重要です.

菊池さんのこの記事もおすすめ.
http://www.atmarkit.co.jp/fdotnet/special/cs20review02/cs20review02_04.html
Posted by NyaRuRu at 2008年08月06日 21:39
ほー。なるほど。そういうことですね。
GetLinesから暗黙的に生成されるIEnumerator<T>が、Disposeメソッド呼び出しを正しく実装するためにも、 IDisposableが必要ということですね。
Posted by Gushwell at 2008年08月07日 06:23
より広い意味で,並列型/読み出し駆動/書き込み駆動型パイプライン連鎖の違いついて,こちらでも書いています.
よろしければあわせてどうぞ.
http://d.hatena.ne.jp/NyaRuRu/20080130/p1
Posted by NyaRuRu at 2008年08月08日 10:29
> よろしければあわせてどうぞ.
> http://d.hatena.ne.jp/NyaRuRu/20080130/p1

ありがとうございます。
頭の回転の遅い僕にはすぐに理解できない部分もあるので
あとでじっくり読んでみます。
Posted by gushwell at 2008年08月08日 23:42
 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/51591837