4

私はしばらくイテレータを使用しており、気に入っています。

しかし、よく考えてみたものの、「イテレータを認識するコンパイラ」の実装方法がわかりませんでした。私もそれについて調査しましたが、コンパイラ設計のコンテキストで状況を説明するリソースを見つけることができませんでした。

詳しく言うと、イテレータに関する記事のほとんどは、目的の動作を実装するある種の「魔法」があることを暗示しています。彼らは、実行がどこにあるか(最後の「yield return」が見られる場所)に従うために、コンパイラがステートマシンを維持することを示唆しています。私は、遅延評価を可能にする Iterator のこのプロパティに特に興味があります。

ところで、私はステート マシンが何であるかを知っており、既にコンパイラの設計コースを受講しており、Dragon Book を研究しています。しかしどうやら、私が研究したことを csc の「魔法」と関連付けることはできないようです。

知識や差別的な考えは大歓迎です。

4

2 に答える 2

5

見た目よりも簡単です。コンパイラは反復子関数を個々のチャンクに分解できます。yieldチャンクはステートメントごとに分割されます。

ステート マシンは、現在どのチャンクにいるのかを追跡するだけでよく、次にイテレータを呼び出すと、このチャンクに直接ジャンプします。また、すべてのローカル変数を追跡する必要があります (もちろん)。

次に、いくつかの特殊なケース、特に s を含むループを考慮する必要がありますyield。幸いなことに、IL (ただし C# 自体ではない) では、ループgotoにジャンプて再開することができます。

非常に複雑なエッジ ケースがいくつかあることに注意してください。たとえば、C# では、関数を に残し、後で関数を再開し、クリーンアップを実行し、例外を再スローすることが非常に困難 (不可能?) であるため、ブロック内で許可yieldされません。スタックトレースを保持します。finallyyield

Eric Lippert がプロセスの詳細な説明を投稿しました。(彼がリンクしている記事も読んでください!)

于 2009-07-13T09:00:47.010 に答える
1

私が試みることの 1 つは、C# で短い例を作成し、コンパイルしてから、Reflector を使用することです。この「利回り」は単なる構文糖衣にすぎないと思うので、逆アセンブラの出力でコンパイラがそれをどのように処理するかを確認できるはずです。

しかし、まあ、私はこれらのことについてあまり知らないので、完全に間違っているかもしれません。

于 2009-07-13T08:59:35.813 に答える