This is how closures work, they capture variables, not values. So j
will be changed.
If you don't want that, you can do this:
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
is still captured by the closure, but not modified. Only the copy k
is modified.
Edit:
You correctly note that this won't work for reference types. In that case k = j
stores a copy of a reference to an object. There's still one copy of the object being referenced, so any modifications to that object will effect both variables.
Here's an example of how you would use the closure for a reference type and not update the original variable:
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; }
}
However, strings being immutable reference types, you actually can just say k = j
, unlike with arbitrary reference types. One way to think of the immutability is that every time you update the value of a string, you are actually creating a new instance. So k = k + "1"
is like saying k = new String(k + "1")
. At that point, it's no longer a reference to the same string as j
.