Confessions of a .NET Developer!

Tricky delegates

One day I stumbled upon a curious thing that I noticed while working with delegates.
Let me explain with an example:

using System;
using System.Collections.Generic;

namespace Weird
{
    class Program
    {
        //Delegate declared
        private delegate void ShowValue();

        static void Main(string[] args)
        {
            List<ShowValue> lst = new List<ShowValue>();

            for (int j = 0; j < 5; j++)
            {
                //Instantiating the delegates
                lst.Add(delegate { Console.WriteLine(j); });
            }

            //Invoking the delegates
            //for (int i = 0; i < 5; i++)
            //{
            //    lst[i]();
            //}           
            //In short, using ForEach extension
            lst.ForEach((ShowValue sv) => { sv(); });

            Console.ReadLine();
        }
    }
}

So I have declared a delegate, instantiating and adding them into a List and then invoking them later.
What do you think is the answer? Most of you might be thinking its 0 1 2 3 4. Not quite correct!

This is the result:

Result

Result


Suprising isn’t it!
Now how did that happen, I started investigating. I started to read John Skeet’s C# in Depth, from here I got the idea. The thing is, the delegate actually captures the variable i. Behind the scene, when we declare a delegate, a separate class is created by the compiler which derives from the MultiCastDelegate class. The delegate instance in the for-loop will create a reference to the variable i. So each time it’s instantiated, it actually refers to the same variable. After the loop gets over, i will be 5 and hence when invoked, 5 will be printed.

For the solution, well its quite simple. Here it goes, first the code:

class Program
    {
        private delegate void ShowValue();

        static void Main(string[] args)
        {
            List<ShowValue> lst = new List<ShowValue>();

            for (int j = 0; j < 5; j++)
            {
                int k = j;
                lst.Add(delegate { Console.WriteLine(k); });
            }

            //for (int i = 0; i < 5; i++)
            //{
            //    lst[i]();
            //}           
            //In short, using ForEach extension
            lst.ForEach((ShowValue sv) => { sv(); });

            Console.ReadLine();
        }
    }

The only change I made is to add a new variable k in the for loop. The trick is, as a new k variable is created for every loop, the delegate will always capture a new k and hence references a different variable. And the result will be: 0 1 2 3 4

FinalResult

FinalResult

Perfect! Hope you got the idea.
Happy Coding! 🙂

Advertisements

June 30, 2011 - Posted by | C Sharp

1 Comment »

  1. very nice article dude…
    if there is a voting system here i will give you full marks…….
    learning new thing today………

    Thanks for sharing……

    Comment by pritesharyan | October 13, 2011 | Reply


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

%d bloggers like this: