Closing behavior

This function returns two different values ​​depending on how it is called. I understand that Closures are closed on variables, not on values, and I expected that the values ​​returned from the second call would be the same no matter what the function is called

static Func<int, int,int> Sum() { var test = 1; return (op1, op2) => { test = test + 1; return (op1 + op2) + test; }; } 

Here is the challenge:

 var mFunc = Sum(); Console.WriteLine("Calling Sum(1,1) with Invoke() " + Sum().Invoke(1, 1)); Console.WriteLine("Calling Sum(2,2) with Invoke() " + Sum().Invoke(2, 2)); Console.WriteLine("Calling mFunc(1,1)" + mFunc(1, 1)); Console.WriteLine("Calling mFunc(2,2)" + mFunc(2, 2)); Console.Read(); 

Result of using Invoke:

 4 6 

Result of using the assigned variable:

 4 7 

Why does using Invoke change closure behavior?

+6
source share
1 answer

Each time you call Sum , you create a separate test delegate that closes the new test variable. The difference is not whether you use Invoke , but whether you use the result of a new call to Sum() .

To demonstrate this, you can simply change your calls to:

 var mFunc = Sum(); Console.WriteLine("Calling mFunc(1,1) with Invoke() " + mFunc.Invoke(1, 1)); Console.WriteLine("Calling mFunc(2,2) with Invoke() " + mFunc.Invoke(2, 2)); Console.WriteLine("----------"); Console.WriteLine("Calling mFunc(1,1)" + mFunc(1, 1)); Console.WriteLine("Calling mFunc(2,2)" + mFunc(2, 2)); Console.Read(); 

Or you can call Sum every time instead:

 var mFunc = Sum(); Console.WriteLine("Calling Sum()(1,1) with Invoke() " + Sum().Invoke(1, 1)); Console.WriteLine("Calling Sum()(2,2) with Invoke() " + Sum().Invoke(2, 2)); Console.WriteLine("----------"); Console.WriteLine("Calling Sum()(1,1)" + Sum()(1, 1)); Console.WriteLine("Calling Sum()(2,2)" + Sum()(2, 2)); Console.Read(); 

Of course, you don't need any parameters to demonstrate this:

 static Action Increment() { int test = 1; return () => { Console.WriteLine(test); test++; }; } 

Then:

 // New delegate for each call Increment()(); // Prints 1 Increment()(); // Prints 1 again Increment()(); // Prints 1 again // Same delegate three times var action = Increment(); action(); // Prints 1 action(); // Prints 2 action(); // Prints 3 
+16
source

All Articles