Closures in CSharp

Closures are an interesting feature for a language. I have heard a lot of questions around how we can declare closures in C# and hence I thought to start a blog on it. Over the internet, there are lots of examples on closures available which are taking help of functional languages like F#, yes it is very important in perspective of these languages as those are easy to declare and also inherently supported yet other languages like C# or VB.NET can also take help of these feature. Lets take a look how C# can take help of closures in this post.

What is a Closure? 

Closures may be defined as a set of behaviour or instructions that are encapsulated as an object such that it could be sent to other object yet can hold the context of the caller.  In other words, a closures are special object that are encapsulated into an object but can hold the context of the caller.

In C# we define closures using delegates. In C# 3.0 we have language support to easily declare a delegate in a program. This widely increases the use of delegates in the program using lamda expressions. Lets put the closures in terms of some examples.



static void Main(string[] args)
{

    int i = 20;
    Action myAction = () => Console.WriteLine("value of i = {0}", i);

    Program.RunMe(myAction);
    Console.ReadLine();

}

public static void RunMe(Action myaction)
{
    if(myaction != null)
        myaction();
}

When you run the above code, you will find that the 20 will be printed on the screen which is run from the method RunMe. Yes, the lamda expression ensures that the instruction set which it specifies is encapsulated within a closure so that the object could be sent on any other objects. As you can see, I am using the contextual variable i from within the RunMe method, hence you can say that myAction forms a closure in C#.

If you are thinking how language implements closures, you must read my blog "Internals of Delegates" from my Internals series where I have showed you how language implementers achieved that. You can also read about Internals of LINQ for better understanding of LINQ and Lamba expressions.

Language implementers allow us to easily declare lambda expressions by giving few delegates already defined inside the framework. To name a few are Action, Action, Action .... Or few others which returns a result using Func, Func, Func ....  These delegates comes very handy while we declare our own closures and pass it to some external methods. Lets look some better example now : 

static void Main(string[] args)
{

    List<MyClass> lstofclass = new List<MyClass>
    {
        new MyClass { Name = "Abhishek", Credit=3000},
        new MyClass { Name= "Dhananjay", Credit= 2000},
        new MyClass { Name = "Kunal", Credit=6000},
        new MyClass { Name= "Abhijit", Credit=9000}
    };

    var items = lstofclass.Where(item => item.Credit > 3000);

    Program.ForEach<MyClass>(items, x => Console.WriteLine("Name : {0}", x.Name));

    Console.ReadLine();

}

public static void ForEach<T1>(IEnumerable<T1> source, Action<T1> myaction)
{
    foreach (var x in source)
        myaction(x);
}

Now in the above example, I have declared a list of object with two properties, Name and Credit. Now I am filtering the list using Where extension method defined in the framework. The Where is an extension method which takes a closure as argument and filters the data according to what we define inside. To understand how this is done, lets take an example of how a normal foreach loop into one that implements closures.



We pass items as argument for our Foreach and a closure which prints the name. Now from the Foreach loop, I just call the method directly using normal foreach.  I hope you understand the concept. Try my sample application to understand it better.

Download Sample -26KB


Interesting thoughts 

Now closures can sometimes be misleading. There are few things that you need to consider important and you must know before working with closures. As I told you that closures can access contextual values from the caller program, yet it points to the latest value rather than the value when it is created. Lets take an example to make it clear  :

string x = "Hello! This is First Message";

Action myAction = () => Console.WriteLine(x);

x = "The value is changed here";

myAction();

Console.ReadLine();

If you run this code, you will see the output is "The value is changed here". Hence you should remember the closures point to the latest value of the contextual variable when it is called rater than when it is created.

Even if you declare x as integer, yet it will show up the latest value.
So why this happens, actually C# compiler create a new class which holds the value X inside it. When we invoke the member, it creates an object of the (compiler generated) class and pass the latest value. Hence you  would see only the latest value of context. Hence we can say Closures close over variable rather than value.

There is an interesting blog by Eric where he showed why closures over loops are harmful which you can read for further interesting reading.

Closing Note

In our current day programming, Closures really holds a special position. We have increased the usage of closures in our program yet knowing the fact what it is capable of. In this blog post, I have tried to make you engulf some of the interesting facts around closures of C#, but there is sea around you and its time for you to discover newer facts about it. Go on, use it in your program, and write to me if you find anything interesting.

Thank you for reading.
Keep in touch.
Shout it Submit this story to DotNetKicks Bookmark and Share
Read Disclaimer Notice

3 comments:

ProDE said...

Hi, I like this blog.

Gabriel Rodriguez said...

Simple but good explanation of Closures in C#. Thanks.

Anonymous said...

Good one Abhishek !

Post a Comment

Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.

Author's new book

Abhishek authored one of the best selling book of .NET. It covers ASP.NET, WPF, Windows 8, Threading, Memory Management, Internals, Visual Studio, HTML5, JQuery and many more...
Grab it now !!!