IEnumerable, IEnumerator ってドリンクサーバみたいなイメージ

ツイッターの文字数制限は、思いついたことを(ここに)書きなぐろうと思わせる動機になる便利なやつである。字数制限の中で意図を伝えにくいので、とりあえず文章や絵を書いてしまえという気にさせてくれる。

※ あくまで、脳内の4〜5次元情報を2次元化したものです。

.NET の interface は色々な用途で使用されるが、多くのインターフェースは「共通した振る舞い」を定義していて、そのインターフェースによって定義される振る舞いを理解するだけで、実装しているすべてのオブジェクトをうまく扱えうことができるようになります。というわけで、neue cc - LINQの仕組みと遅延評価の基礎知識 の挿絵をみて*1放ったツイート「IEnumerable ってドリンクサーバみたいなイメージ」について、ちょっと書き殴っておきます。
ドリンクサーバって、こういうやつですね。この絵にはボタンはありませんが、ボタンを押すとコップ1杯分のドリンクが抽出される便利なやつです。
やあ、絵も説明も無理すぎる^^

GetEnumerator() で取り出した後は、MoveNext() を呼ぶたびに Current の中身が入れ替わります。中身がどのような順序で取り出されるかは、基になった IEnumerable に依存していて List の場合には格納されている要素順に従って取り出されます。からっぽになった状態で MoveNext() を呼び出すと、戻り値が false になって Current には何も取り出されません。*2


coffee から要素を取り出そうとすると、coffee は beans から豆を取り出そうとします。beans から豆を取り出そうとすると beans は odd から次に使うべき豆の番号を取得しようとします。odd から使うべき豆の番号を取り出そうとすると、在庫リスト list から次に使うべき豆番号を取得します。逆に言えば、誰かが coffee から新しいコーヒーを取り出そうとしないかぎり、在庫リストから豆番号を取り出すようなことは発生しません。(遅延評価)
メソッドチェインでは、通常は次の要素が手に入るまで MoveNext() を呼び続けます。このため、リストが { 1, 4, 3 } のようになっていた場合、最初の MoveNext() で 1 が取り出され、順調に進んで1番のコーヒーがでてきます。2回目の MoveNext() では、4 が取り出されますが odd についた Where() の条件によってこの 4 は捨てられてしまい、beans には渡りません。結果として、beans は自動的に MoveNext() を再発行して odd から新しい豆番号を手に入れようとします。そして、 3 が取り出され、最終的に coffee に対する2回目の MoveNext() では3番のコーヒーが取得されることになります。

やっぱ書くんじゃなかった、ぐだぐだ。「取り出す」と表現すると、まるで list の要素が減るように見えますが、減りません。せめて注文 Queue にしたらよかった...?(Queue は Queue で Dequeue しないと減らないわけだが)

*1:挿絵だけを見てのつぶやきなんです、はい

*2:最初の MoveNext を呼ぶ前や、MoveNext が false になった後の Current にアクセスすると、例外 InvalidOperationException がスローされます