クロージャーを作成すると、コンパイラーは、キャプチャーされた各変数のメンバーを持つ型を作成します。あなたの例では、コンパイラは次のようなものを生成します。
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
public string foo;
public void <Main>b__0()
{
Console.WriteLine(this.foo);
}
}
デリゲートには、キャプチャされた変数を後で使用できるように、この型への参照が与えられます。残念ながら、 のローカル インスタンスfoo
もここを指すように変更されているため、ローカルで変更を加えるとデリゲートが同じオブジェクトを使用するため影響を受けます。
ご覧のとおり、の永続性はfoo
プロパティではなくパブリック フィールドによって処理されるため、現在の実装では不変性のオプションさえありません。あなたが望むものは次のようなものでなければならないと思います:
var foo = "hello";
Action bar = [readonly foo]() => Console.WriteLine(foo);
bar();
foo = "goodbye";
bar();
不器用な構文を許してください。しかし、アイデアは、この生成された型を出力するようにコンパイラに示唆する方法でfoo
キャプチャされていることを示すことです。readonly
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
public readonly string foo;
public <>c__DisplayClass1(string foo)
{
this.foo = foo;
}
public void <Main>b__0()
{
Console.WriteLine(this.foo);
}
}
これにより、特定の方法で必要なものが得られますが、コンパイラの更新が必要になります。