What Are 'Closures' in C#

What are 'closures' in C#?

A closure in C# takes the form of an in-line delegate/anonymous method. A closure is attached to its parent method meaning that variables defined in parent's method body can be referenced from within the anonymous method. There is a great Blog Post here about it.

Example:

public Person FindById(int id)
{
return this.Find(delegate(Person p)
{
return (p.Id == id);
});
}

You could also take a look at Martin Fowler or Jon Skeet blogs. I am sure you will be able to get a more "In Depth" breakdown from at least one of them....

Example for C# 6:

public Person FindById(int id)
{
return this.Find(p => p.Id == id);
}

which is equivalent to

public Person FindById(int id) => this.Find(p => p.Id == id);

What are 'closures' in .NET?

I have an article on this very topic. (It has lots of examples.)

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.

The general feature of closures is implemented in C# by anonymous methods and lambda expressions.

Here's an example using an anonymous method:

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=1
counter=2

Here we can see that the action returned by CreateAction still has access to the counter variable, and can indeed increment it, even though CreateAction itself has finished.

Are Lambda expressions in C# closures?

A lambda may be implemented using a closure, but it is not itself necessarily a closure.

A closure is "a function together with a referencing environment for the non-local variables of that function.".

When you make a lambda expression that uses variables defined outside of the method, then the lambda must be implemented using a closure. For example:

int i = 42;

Action lambda = () => { Console.WriteLine(i); };

In this case, the compiler generated method must have access to the variable (i) defined in a completely different scope. In order for this to work, the method it generates is a "function together with the referencing environment" - basically, it's creating a "closure" to retrieve access to the variable.

However, this lambda:

Action lambda2 = () => { Console.WriteLine("Foo"); }

does not rely on any "referencing environment", since it's a fully contained method. In this case, the compiler generates a normal static method, and there is no closure involved at all.

In both cases, the lambda is creating a delegate ("function object"), but it's only creating a closure in the first case, as the lambda doesn't necessarily need to "capture" the referencing environment in all cases.

C# closure variable scope

Let's consider:

static Action getAction(Foo obj)
{
return () => Console.WriteLine(obj.name);
}

The closure is over the parameter obj; this obj is a reference passed by value, so if a caller does:

x = someA();
var action = getAction(x);
x = someB(); // not seen by action

then the closure is still over the original value, because the reference (not the object) is copied when passing it to getAction.

Note that if the caller changes values on the original object, this will be seen by the method:

x = someA();
var action = getAction(x);
x.name = "something else"; // seen by action

Inside the getAction method, it is basically:

var tmp = new SomeCompilerGeneratedType();
tmp.obj = obj;
return new Action(tmp.SomeCompilerGeneratedMethod);

with:

class SomeCompilerGeneratedType {
public Foo obj;
public void SomeCompilerGeneratedMethod() {
Console.WriteLine(obj.name);
}
}

C# - How do closures work in lambdas and how does the garbage collector deal with them?

It does it through a closure

A closure is a block of code which can be executed at a later time, but which keeps and maintains the environment in which it was first created via the use of a compiler generated class. it can still use the local variables even when the method has finished, the garbage collector maintain reference counts to anything it needs and nothing gets collected which shouldn't be

How do closures work behind the scenes? (C#)

The compiler (as opposed to the runtime) creates another class/type. The function with your closure and any variables you closed over/hoisted/captured are re-written throughout your code as members of that class. A closure in .Net is implemented as one instance of this hidden class.

That means your count variable is a member of a different class entirely, and the lifetime of that class works like any other clr object; it's not eligible for garbage collection until it's no longer rooted. That means as long as you have a callable reference to the method it's not going anywhere.

Are these examples C# closures?

Yea, a closure is nothing more than a function that "saves" some variables from the environment in which it is defined. So in both of your examples, the defined action saves the list named subFolders, which can be referenced by the functions even after the local variable is out of scope. The filter variable in the second example is also saved by the defined function.

A more precise definition here

When to use closure?

Closures are simply great tools. When to use them? Any time you like... As has already been said, the alternative is to write a class; for example, pre C# 2.0, creating a parameterised thread was a real struggle. With C# 2.0 you don't even need the `ParameterizedThreadStart' you just do:

string name = // blah
int value = // blah
new Thread((ThreadStart)delegate { DoWork(name, value);}); // or inline if short

Compare that to creating a class with a name and value

Or likewise with searching for a list (using a lambda this time):

Person person = list.Find(x=>x.Age > minAge && x.Region == region);

Again - the alternative would be to write a class with two properties and a method:

internal sealed class PersonFinder
{
public PersonFinder(int minAge, string region)
{
this.minAge = minAge;
this.region = region;
}
private readonly int minAge;
private readonly string region;
public bool IsMatch(Person person)
{
return person.Age > minAge && person.Region == region;
}
}
...
Person person = list.Find(new PersonFinder(minAge,region).IsMatch);

This is fairly comparable to how the compiler does it under the bonnet (actually, it uses public read/write fields, not private readonly).

The biggest caveat with C# captures is to watch the scope; for example:

        for(int i = 0 ; i < 10 ; i++) {
ThreadPool.QueueUserWorkItem(delegate
{
Console.WriteLine(i);
});
}

This might not print what you expect, since the variable i is used for each. You could see any combination of repeats - even 10 10's. You need to carefully scope captured variables in C#:

        for(int i = 0 ; i < 10 ; i++) {
int j = i;
ThreadPool.QueueUserWorkItem(delegate
{
Console.WriteLine(j);
});
}

Here each j gets captured separately (i.e. a different compiler-generated class instance).

Jon Skeet has a good blog entry covering C# and java closures here; or for more detail, see his book C# in Depth, which has an entire chapter on them.

Deep diving into the implementation of closures

It helps to look at the fully de-compiled code:

// Decompiled with JetBrains decompiler
// Type: Program
// Assembly: test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: D26FF17C-3FD8-4920-BEFC-ED98BC41836A
// Assembly location: C:\temp\test.exe
// Compiler-generated code is shown

using System;
using System.Runtime.CompilerServices;

internal static class Program
{
private static void Main()
{
Program.\u003C\u003Ec__DisplayClass1 cDisplayClass1 = new Program.\u003C\u003Ec__DisplayClass1();
cDisplayClass1.x = 1;
// ISSUE: method pointer
Action action = new Action((object) cDisplayClass1, __methodptr(\u003CMain\u003Eb__0));
cDisplayClass1.x = 3;
action();
Console.WriteLine(cDisplayClass1.x);
}

[CompilerGenerated]
private sealed class \u003C\u003Ec__DisplayClass1
{
public int x;

public \u003C\u003Ec__DisplayClass1()
{
base.\u002Ector();
}

public void \u003CMain\u003Eb__0()
{
Console.WriteLine(this.x);
this.x = 2;
}
}
}

Specifically, look at how Main got re-written:

  private static void Main()
{
Program.\u003C\u003Ec__DisplayClass1 cDisplayClass1 = new Program.\u003C\u003Ec__DisplayClass1();
cDisplayClass1.x = 1;
// ISSUE: method pointer
Action action = new Action((object) cDisplayClass1, __methodptr(\u003CMain\u003Eb__0));
cDisplayClass1.x = 3;
action();
Console.WriteLine(cDisplayClass1.x);
}

You see that the x being affected is attached to the closure class generated from the code. The following line changes x to 3:

    cDisplayClass1.x = 3;

And this is the same x that the method behind action is referring to.



Related Topics



Leave a reply



Submit