Like C # lambda capture variables

Why does the following code print 11 twice?

int i = 10; Action fn1 = () => Console.WriteLine(i); i = 11; Action fn2 = () => Console.WriteLine(i); fn1(); fn2(); 

Exit 11 11

According to the answers in this post - How do I say lambda functions to capture a copy instead of a reference to C #? - lambda transferred to class with copy of captured variable. If so, should my sample not print 10 and 11?

Now that the lambda is capturing by reference, how does it affect the lifetime of the captured variable. For example, suppose the above code snippet was in a function and the scope was global for the variable:

 class Test { Action _fn1; Action _fn2; void setActions() { int i = 10; _fn1 = () => Console.WriteLine(i); i = 11; _fn2 = () => Console.WriteLine(i); } static void Main() { setActions(); _fn1(); _fn2(); } } 

In this case, the variable I did not go out of scope with the action? So, the actions left with a link to the dangling pointer?

+7
closures c # lambda
source share
3 answers

If so, should my sample not print 10 and 11?

No, because you have only one variable - fn1 captures the variable, not its current value. So this method:

 static void Foo() { int i = 10; Action fn1 = () => Console.WriteLine(i); i = 11; Action fn2 = () => Console.WriteLine(i); fn1(); fn2(); } 

translates as follows:

 class Test { class MainVariableHolder { public int i; public void fn1() => Console.WriteLine(i); public void fn2() => Console.WriteLine(i); } void Foo() { var holder = new MainVariableHolder(); holder.i = 10; Action fn1 = holder.fn1; holder.i = 11; Action fn2 = holder.fn2; fn1(); fn2(); } } 

This will also answer your second point: the variable "rises" into the class, so its service life is effectively extended as long as the delegate is alive.

+6
source share

Indeed, the class is generated because it placed the captured variables, not their values. So, when lamba is executed, the runtime will check the current value of i , which is 11, since you updated this before you call the lambda. That is why you see it. To test this argument, you can reorder your statements as shown below:

 int i = 10; Action fn1 = () => Console.WriteLine(i); fn1(); i = 11; Action fn2 = () => Console.WriteLine(i); fn2(); 
0
source share

It prints twice due to deferred execution, and not because of the way it captures variables.

When execution is delayed, it will print the last value of i, since I is what is captured, not the value.

-one
source share

All Articles