- Introduction
- Whats in a Lambda?
- Understanding Closures
- Currying
- Summary
Understanding Closures
Suppose a Lambda expression uses a local variable and the Lambda is returned from its context. The default behavior is that local variables are cleaned up as the stack memory for that scope is cleaned up. If the default behavior were permitted for Lambda expressions, then the local variables referred to by the Lambda expressions would be invalid, resulting in a null reference exception.
To prevent invalid references, the compiler creates what’s called a closure for the Lambda expression. A closure is a wrapper class that contains the Lambda expression and fields that contain copies of the local variables. Since the closure is an object created with new, it’s not cleaned up when the scope exits. The result is that the Lambda expression is valid, the reference to the copy of the local variable is valid, and everything works fine. All of this work is managed by the compiler.
Listing 2 demonstrates a Lambda expression that’s used across scopes and that uses a local variable. The image in Figure 1 shows the ILDASM showcasing the compiler-generated closure.
Listing 2 Lambda expression used across scopes.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LambdaExpressions { class Program { static void Main(string[] args) { string myName = "Paul Kimmel"; Action<string> print = s => Console.WriteLine(s + " " + myName); print("Hello,"); Console.ReadLine(); } } }
Figure 1 The class c__DisplayClass1 represents the closure. If you look at the MSIL for DisplayClass, you’ll see the myName field, the locally-referenced enclosed variable.
Notice in Figure 1 that the c__DisplayClass1 class is defined, but we didn’t define it in the code—hence, it must be compiler-generated. Also, notice that the Lambda expression is used only in the local scope. This is one of those instances where it’s easier to write a compiler that always does only one thing. Thus, if a Lambda expression uses a local variable, a closure will always be defined, whether or not that Lambda expression leaves the scope.