Когда вы создаете замыкание, компилятор создает для вас тип, в котором есть члены для каждой захваченной переменной. В вашем примере компилятор сгенерирует что-то вроде этого:
[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);
}
}
Это даст вам то, что вы хотите определенным образом, но потребует обновления компилятора.