Closures in c#


As a c# developers we write a lot of lambda expressions. And with lambda expressions we can access variables outside the expression block.

For Example:

class Program

{

static Func<int,int> Add;

static void Main(string[] args)

{

int x = 5;

int y = 8;

Add = res => { return x + y; };

Console.WriteLine(Add(y));

Console.ReadLine();

}

}

Outer variables captured by lambda expressions is called a Closures. Closures means that the inner scope function closed over variable from outer scope.

What actually happened when we use closures?

The compiler generate a new class to hold the closures parameters passes into the inner function.

By decompile this code above with ILSpy, we can see the generated class for the closures variable

// Nested Types     .class nested private auto ansi sealed beforefieldinit ‘<>c__DisplayClass1’         extends [mscorlib]System.Object

{         .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (             01 00 00 00         )
// Fields

.field public int32 x
.field public int32 y         // Methods         .method public hidebysig specialname rtspecialname              instance void .ctor () cil managed          {             // Method begins a        } // end of method ‘<>c__DisplayClass1’::.ctor

.method public hidebysig

instance int32 ‘<Main>b__0’ (                 int32 res             ) cil managed          {             // Method begins at RVA 0x2058             // Code size 19 (0x13)             .maxstack 2             .locals init (                 [0] int32 CS$1$0000             )             IL_0000: nop             IL_0001: ldarg.0             IL_0002: ldfld int32 ClosuresDemo.Program/'<>c__DisplayClass1′::x             IL_0007: ldarg.0             IL_0008: ldfld int32 ClosuresDemo.Program/'<>c__DisplayClass1′::y             IL_000d: add             IL_000e: stloc.0             IL_000f: br.s IL_0011             IL_0011: ldloc.0             IL_0012: ret         } // end of method ‘<>c__DisplayClass1′::'<Main>b__0’     }

// end of class <>c__DisplayClass1

DisplayClass1 is the generated class by the compiler that used to capture the variables into the lambda expression scope.

Here is another example of allocation is done behind the scenes by the compiler

static void HandleTcpClient(TcpClient tcpClient)

{

Task.Factory.StartNew(() =>

{

int i = -1;

// Get a stream object for reading and writing

NetworkStream stream = tcpClient.GetStream();

// Buffer for reading data

Byte[] bytes = new Byte[256];

String data = null;

while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)

{

// Translate data bytes to a ASCII string.

data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);

Console.WriteLine(“Received: {0}”, data);

// Process the data sent by the client.

data = data.ToUpper();

byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);

// Send back a response.

stream.Write(msg, 0, msg.Length);

Console.WriteLine(“Sent: {0}”, data);

}

});

In this case, each time this function is called, the compiler allocates a new object that holds tcpClient field.

Danger with Closures

Changing a Variable inside and outside the Lambda expression:

string closureCapture = “Create a variable before the lambda declaration”;

AccessClosureVariable = () =>

{

Console.WriteLine(closureCapture);

closureCapture = “Changing the variable value inside the lambda scope”;

};

closureCapture = “Changing variable value before the execution”;

AccessClosureVariable();

Console.WriteLine(closureCapture);

closureCapture = “Changing variable value before the second execution”;

AccessClosureVariable();

Console.WriteLine(closureCapture);

The output of this example is:

Changing variable value before the execution

Changing the variable value inside the lambda scope

Changing variable value before the second execution

Changing the variable value inside the lambda scope

The compiler generate the captured variable, and not his value. That means creating the anonymous method doesn’t read the closure value.

This example illustrates that the closure variable is the same as the outer scope variable.

Summery

Closures can simplify our code.

In terms of G.C and performance, in most cases closure is not an issue, but if we capture a large object or an expensive in terms of memory footprint it can be significant.

We need to be careful of changing closures inside or outside the lambda scope.

Advertisements

About Idan Reuven

Idan is Microsoft Certified Proffesional Developer (MCPD) Idan Working As Senior Software developer. and specialize in professional application development with WPF, WCF, Entity Framework, XAML, HTML 5, Java Script , jQuery, MVC, MVVM, C#, C++, SQL Server Technologies.
This entry was posted in .NET, .NET 4.5, C# 5 and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s