これがクロージャーの仕組みであり、値ではなく変数をキャプチャします。なのでj
変更になります。
それを望まない場合は、次のようにすることができます。
static void Main(string[] args)
{
int j = 0;
Func<int> f = () =>
{
int k = j;
for (int i = 0; i < 3; i++)
{
k += i;
}
return k;
};
int myStr = f();
Console.WriteLine(myStr);
Console.WriteLine(j);
Console.Read();
}
j
クロージャーによって引き続きキャプチャされますが、変更されません。コピーのみk
が変更されます。
編集:
これは参照型では機能しないことに正しく注意してください。その場合k = j
、オブジェクトへの参照のコピーを格納します。参照されているオブジェクトのコピーが 1 つ残っているため、そのオブジェクトを変更すると両方の変数に影響します。
元の変数を更新せずに、参照型にクロージャーを使用する方法の例を次に示します。
static void Main(string[] args)
{
Foo j = new Foo(0);
Func<Foo> f = () =>
{
Foo k = new Foo(j.N); // Can't just say k = j;
for (int i = 0; i < 3; i++)
{
k.N += 1;
}
return k;
};
Console.WriteLine(f().N);
Console.WriteLine(j.N);
Console.Read();
}
public class Foo
{
public int N { get; set; }
public Foo(int n) { N = n; }
}
ただし、文字列は不変の参照型であるため、任意の参照型とは異なり、実際には単に と言うことができます。k = j
不変性を考える 1 つの方法は、文字列の値を更新するたびに、実際には新しいインスタンスを作成していることです。と言うk = k + "1"
ようなものk = new String(k + "1")
です。その時点で、 と同じ文字列への参照ではなくなりますj
。