According to C # in a nutshell:
lambda expression can refer to local variables and parameters of the method in which it is defined (external variables).
Example:
int factor = 2; Func<int, int> multiplier = n => n * factor; Console.WriteLine (multiplier (3));
Captured variables and closure:
External variables referenced by the lambda expression are called captured variables . A lambda expression that captures variables is called a closure .
Captured variables are evaluated when delegation is actually called, and not when variables have been captured
For instance:
int factor = 2; Func<int, int> multiplier = n => n * factor; factor = 10; Console.WriteLine (multiplier (3));
Lambda expressions can themselves update captured variables:
int seed = 0; Func<int> natural = () => seed++; Console.WriteLine (natural()); // 0 Console.WriteLine (natural()); // 1 Console.WriteLine (seed); // 2
Captured variables extend the life of the delegate.
In the following example, a local variable seed usually disappears from the scope when the execution completes naturally. But since the seed was captured, its service life extended to the resolution of the captured delegate, of course:
static Func<int> Natural() { int seed = 0; return () => seed++;
A local variable created within a lambda expression is unique when invoked with a delegate instance. If we reorganize our previous example to create seeds in the lambda expression, we get another (in this case, undesirable) result:
static Func<int> Natural() { return() => { int seed = 0; return seed++; }; } static void Main() { Func<int> natural = Natural(); Console.WriteLine (natural());
Capture is internally implemented by βliftingβ the captured variables into private class fields. When the method is called, an instance of the class and bound to the delegate member instance.
Capturing variable iterations
When you commit an iteration variable for a for loop, C # treats this variable as though it was declared outside the loop. This means that the same variable is captured at each iteration. The following program writes 333 instead of 012:
Action[] actions = new Action[3]; for (int i = 0; i < 3; i++) actions [i] = () => **Console.Write (i)**;
Each closure (in bold) captures the same variable, i. (This actually does if you think that I am a variable whose value is stored between iterations of the loop; you can even explicitly change I inside the loop body if you want.) The consequence of this is that when delegates are called later, each delegate sees the value during the call is 3.
The above example equals this:
Action[] actions = new Action[3]; int i = 0; actions[0] = () => Console.Write (i); i = 1; actions[1] = () => Console.Write (i); i = 2; actions[2] = () => Console.Write (i); i = 3; foreach (Action a in actions) a(); // 333
Revert a change to a note in C # 5:
Prior to C # 5.0, foreach loops worked the same way.
Consider the following example:
Action[] actions = new Action[3]; int i = 0; foreach (char c in "abc") actions [i++] = () => Console.Write (c); foreach (Action a in actions) a();
it will output ccc in C # 4.0 , but in C # 5.0 it will output abc .. p>
Quote from the book:
This caused considerable confusion: unlike the for loop, the iteration variable in the foreach loop is unchanged, and therefore one would expect it to be considered local to the loop body. The good news is that it has been fixed in C # 5.0, and the example above now writes "abc."
Technically, this is a violation of the change, since recompiling C # 4.0 to C # 5.0 may produce a different result. In general, the C # team is trying to avoid breaking changes; however, in this case, a βbreakβ will almost certainly indicate an undetected error in the C # 4.0 program, and not an intentional dependence on the old behavior.