あなたのフォームにボタンがあるとします。あなたはボタンに無名関数を付けました。 Click
イベント:
void Test()
{
int x = 10;
btn.Click += (sender, e) => { MessageBox.Show(x.ToString()); };
}
これは期待どおりに動作し、10を表示します。ローカル変数にアクセスできることを意味します。私の質問は、どのように、なぜですか?匿名関数はどのようにローカルコンテキストにアクセスできますか?
私が扱っている実際の問題は、私がこの無名関数を通常の関数(イベントハンドラ)にアップグレードする必要があります。しかし、それは変数xへのアクセスを失うことを意味します。それをパラメータとして渡すことはできません。なぜなら、変数を渡すことができないからです。 Click
イベント(シグネチャの不一致)。私はグローバル変数とそのすべてを作成することでこれを回避することができますが、匿名関数はどのようにしてスコープ外のものにアクセスすることが可能になりますか?
回答:
回答№1の場合は10半分の ポイント 匿名関数の中には、指定されたコンテキストを取得できるということがあります。これを行うことができれば非常に便利です。なぜなら、「なぜ」という部分です。
コンパイラがこれを行う方法は、必要な場合に新しいクラスを作成することです。つまり、あなたのコードは次のようなものに変換されます:
void Test()
{
TestHelper helper = new TestHelper();
helper.x = 10;
btn.Click += helper.Method;
}
private class TestHelper
{
public int x = 10;
public void Method(object sender, EventArgs e)
{
MessageBox.Show(x.ToString());
}
}
毎回の使用 x
以内 Test
の使用に変換されます helper.x
適切なインスタンスのために。これは、寿命の異なる変数についても同様です。たとえば、次のようなループがあるとします。
for (int i = 0; i < 10; i++)
{
int x = i;
// Use with some anonymous function
}
新しいインスタンスを作成します。 TestHelper
ループの反復ごとに... while x
宣言されていた 外側 ループは、すべての匿名関数が効果的に共有する単一インスタンスになります。
それがちょうどいいとき this
それがキャプチャされると、コンパイラはインスタンスを作成しますヘルパークラスを作成する代わりに、既存のクラス内のメソッドを使用します。さまざまな変数を取得する可能性のある複数の匿名関数を持つスコープが異なる場合、ヘルパークラスによっては他のヘルパークラスなどのインスタンスへの参照を持つことがあります。