C # closure problem-have you ever been "pitted ?,
Introduction
What is a closure? This term was found only when I read the interview questions.
What problems does closures have in actual projects? Now let's take a look at this unfamiliar term.
If anonymous functions and lamada expressions are used in actual work, you should pay close attention to them.
Problem
What are the output results of this code?
public static void Main(){ Console.WriteLine("Starting."); for (int i = 0; i < 4; ++i) Task.Run(() => Console.WriteLine(i)); Console.WriteLine("Finished. Press <ENTER> to exit."); Console.ReadLine();}
Output result:
Starting.Finished. Press <ENTER> to exit.4444
Are you correct? If not, follow me to find out the underlying reasons.
Problem Solving
public static void Main(){ Console.WriteLine("Starting."); for (int i = 0; i < 4; ++i) { int j = i; Task.Run(() => Console.WriteLine(j)); } Console.WriteLine("Finished. Press <ENTER> to exit."); Console.ReadLine();}
Output result
Starting.Finished. Press <ENTER> to exit.0132
What is the cause analysis closure?
using System;class Test{ static void Main() { Action action = CreateAction(); action(); action(); } static Action CreateAction() { int counter = 0; return delegate { // Yes, it could be done in one statement; // but it is clearer like this. counter++; Console.WriteLine("counter={0}", counter); }; }}
Output
counter=1counter=2
In essence, a closure is a block of code which can be executed at a later time, but which maintains the environment in which it was first created - i.e. it can still use the local variables etc of the method which created it, even after that method has finished executing.
In essence, a closure is a code block that can be executed later, but it still maintains its first environment (Execution context) when it is created) -that is, it can still use the local variables in the method for creating it, even if the method has been executed.
This paragraph cannot be regarded as a definition accurately, but the image is described. No absolute definition is provided here. This is described on the wiki.
C # closures are usually implemented through anonymous functions and lamada expressions.
Let's look at a simple example:
var values = new List<int> { 100, 110, 120 };var funcs = new List<Func<int>>();foreach (var v in values) funcs.Add(() => { //Console.WriteLine(v); return v; });foreach (var f in funcs) Console.WriteLine(f());Console.WriteLine("{0}{0}", Environment.NewLine);funcs.Clear();for (var i = 0; i < values.Count; i++){ //var v2 = values[i];
funcs.Add(() => { var v2 = values[i]; //will throw exception
return v2; });}foreach (var f in funcs) Console.WriteLine(f());
Just a few words
Because ()=>v means "return the current value of variable v", not "return the value v was back when the delegate was created",Closures close over variables, not over values.
Because () => v "returnsCurrent Value of variable v"Instead of the return value of "v" when the delegate is created.Closure "variable" instead of closure "value".
Therefore, the added anonymous function in the "for" loop only returns the variable I rather than the value of I. So when f () is actually executed, I is already the value of values. Count, so it throws "out of the index range". Why is foreach okay? Let's look at the header of the closure.
History
The latter. The C# 1.0 specification actually did not say whether the loop variable was inside or outside the loop body, as it made no observable difference. When closure semantics were introduced in C# 2.0, the choice was made to put the loop variable outside the loop, consistent with the "for" loop.--Eric Lippert
The closure syntax is introduced in C #2.0, and the loop variable is placed out of the loop body. The for and foreach processes are consistent in this respect. However, Microsoft made a "concession" in the use process, and made adjustments to "foreach" in C #5, but did not make any changes to ". The specific changes are as follows:
We are taking the breaking change. In C# 5, the loop variable of a foreach will be logically inside the loop, and therefore closures will close over a fresh copy of the variable each time. The "for" loop will not be changed. --Eric Lippert
In C #5, we made a huge adjustment. The temporary loop variables defined in the "foreach" traversal will be logically restricted in the loop, each loop of "foreach" is a copy of the cyclic variable, so that the closure looks closed (no more ). However, the "for" loop is not modified.
Summary
Anonymous functions and Lambda expressions bring many convenient and simple implementations to our programming, such as writing (List. Max (a) => a. Level ). But we need to be aware that there is still a closure behind these two sweets ). This once again tells our technical staff to "know the truth, but also the truth".
References
Closing over the loop variable considered harmful
Closing over the loop variable, part two
For Loop result in Overflow with Task. Run or Task. Start
Is there a reason for C #'s reuse of the variable in a foreach?
The Beauty of Closures
Future of Code Reading Notes ,)