BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

C# Programming
.NET 3.5+

C# Closures

Closures are usually associated with functional programming languages, where they link a function to its referencing environment, permitting access to variables outside of the function's scope. With the use of delegates, closures are available in C#.

What are Closures?

Lexical closures are most commonly used in functional programming languages. A closure is a special type of function that is linked to its referencing environment, which is the code that defined it. This allows closure functions to use variables from that referencing environment, despite these values not being within the closure's scope. When the function is created, the external variables that it uses are "closed over", meaning that they are bound to the closure function in a way that makes them accessible. Often this means that copies of their values are made when the closure is defined.

Using Closures in C#

In C#, closures can be created using anonymous methods and lambda expressions, depending upon the version of the .NET framework that you are developing against. When you create the function, the variables that it will use that are outside of its visible scope are, in concept, copied and stored with the closure's code. They can then be used whenever the delegate is called. This leads to great flexibility when using such delegates but also introduces the possibility of unexpected bugs. We'll look at these later on in this article. Before we do, let's look at a simple closure.

In the code below, we create an integer value in the "nonLocal" variable. The second statement creates an Action delegate instance, which outputs a message that uses the value of the integer variable. Finally, we run the delegate to see the message appear. The results are probably exactly what you would expect, whether you are used to using closures or not.

int nonLocal = 1;
Action closure = delegate
{
    Console.WriteLine("{0} + 1 = {1}", nonLocal, nonLocal + 1);
};
closure();  // 1 + 1 = 2

We can do exactly the same thing with a lambda expression. Here we are using a statement lambda to output information but an expression lambda is equally valid.

int nonLocal = 1;
Action closure = () =>
{
    Console.WriteLine("{0} + 1 = {1}", nonLocal, nonLocal + 1);
};
closure();  // 1 + 1 = 2

Closures and Out-Of-Scope Variables

With the anonymous method or the lambda expression examples above, the results are as you might expect because the capturing of variables by the closure is not immediately apparent. We can make this more obvious by changing the scope of the delegate.

Consider the following code. Here the closure is held in a class-level Action variable. The Main method calls the SetUpClosure method to initialise the closure before executing it. The SetUpClosure method is important. You can see that the integer variable is created and initialised and then used within the closure. On completion of the SetUpClosure method, this integer variable goes out of scope. However, we are still invoking the delegate after this happens. Now the result is not so obvious. Will it compile and run correctly? Will an exception occur when trying to access the out-of-scope variable? Try executing the code.

class Program
{
    static Action _closure;

    static void Main(string[] args)
    {
        SetUpClosure();
        _closure();     // 1 + 1 = 2
    }

    private static void SetUpClosure()
    {
        int nonLocal = 1;
        _closure = () =>
        {
            Console.WriteLine("{0} + 1 = {1}", nonLocal, nonLocal + 1);
        };
    }
}

You can see that we get the same result as in the original example. This is the closure in action. The "nonLocal" variable was captured, or "closed over", by the delegate code, causing it to remain in scope beyond the normal limits. In fact, it will remain available until the no further references to the delegate remain.

Although we've seen closures working, they aren't really supported by C# and the .NET framework. What really happens is some behind-the-scenes work by the compiler. When you build your project, the compiler generates a new, hidden class that encapsulates the non-local variables and the code you include in the anonymous method or lambda expression. The code is included in a method and the non-local variables are represented as fields. This new class's method is called when the delegate is executed.

The automatically generated class for our simple closure is similar to the following:

[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
    public int nonLocal;

    public void <SetUpClosure>b__0()
    {
        Console.WriteLine("{0} + 1 = {1}", this.nonLocal, this.nonLocal + 1);
    }
}
24 July 2012