这就是闭包的工作方式,它们捕获变量,而不是值。所以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
存储对对象的引用的副本。仍然有一个被引用对象的副本,因此对该对象的任何修改都会影响这两个变量。
这是一个示例,说明如何将闭包用于引用类型而不更新原始变量:
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
,与任意引用类型不同。考虑不变性的一种方法是,每次更新字符串的值时,实际上都是在创建一个新实例。所以k = k + "1"
就像说k = new String(k + "1")
。那时,它不再是对与j
.