Click here to Skip to main content
15,868,016 members
Articles / Programming Languages / C#

Internals of a Delegate

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
26 Jan 2011CPOL8 min read 17.5K   8   6
Internals of a Delegate

Strange Rules of Delegate

Well, in recent times, at least after the introduction of .NET Framework 3.5, the use of Delegates in a program has increased quite a bit. Now almost all people in .NET language must have at least somehow used delegates on their daily programming activities. It might be because of the fact that the use of delegates has been simplified so much with the introduction of lambda expressions in .NET Framework 3.5 and also the flexibility to pass delegates over other libraries for decoupling and inversion of control in applications. Hence, we can say the way of writing code in .NET environment has been changed considerably in recent times.

Introduction

If you want the most simple and somewhat vague idea about delegates, I would say a delegate is actually a reference to a method so that you might use the reference as you use your object reference in your code, you can send the method anywhere in your library or even pass to another assembly for its execution, so that when the delegate is called, the appropriate method body will get executed. Now, to know a more concrete and real life example, I must consider showing you some code:

C#
public delegate int mydelegate(int x);
        public class A
        {
            public mydelegate YourMethod { get; set; }

            public void ExecuteMe(int param)
            {
                Console.WriteLine("Starting execution of Method");
                if (this.YourMethod != null)
                {
                    Console.WriteLine("Result from method : {0}", 
			this.YourMethod(param));
                }
                Console.WriteLine("End of execution of Method");
            }
        }        

        static void Main(string[] args)
        {
            //int x = 20;
            //int y = 50;

            A a1 = new A();

            a1.YourMethod = Program.CallMe;


            a1.ExecuteMe(20);

            Console.Read();
    }
     public static int CallMe(int x)
        {
            return x += 30;
        }
}

In the above code, I have explicitly declared a delegate and named it mydelegate. The name of the delegate will indicate that it is a type that can create a reference to a method which can point to a method which has the same signature as defined in it. Clearly, if you quickly go through the code defined above, the property YourMethod can point to a signature which has the same signature as declared to mydelegate. Hence, I can pass a method CallMe easily to Type A, so that when the object of A calls the delegate, it executes the method CallMe.

This is very interesting, and has a lot of benefits. Thus to ensure we have strong decoupling between two assemblies, you sometimes need to run a code which must be declared somewhere to the caller (just like event handlers) but the library could call it whenever required. In such a scenario, you might consider the use of delegates comes very handy. As a matter of fact, if you say class A is declared somewhere in base libraries and CallMe is declared in your code, you can easily pass the method to base class library easily.

Language Flexibility in the Form of Delegates

The above code shows few basic rules of declaring a delegate in your code. But this is not the end of the topic. C# programmers want the use of delegate more easily than this. So instead of rotting the code by introducing a method CallMe, we have the flexibility of using anonymous delegates in my code as well. To declare an anonymous delegate, I just need to change:

C#
a1.YourMethod = Program.CallMe 

to:

C#
a1.YourCall = delegate(int e)
            {
                return e += 30;
            };

So here I have just written the whole body of CallMe to inline anonymous method construct. You should remember, the concept of anonymous delegate came from .NET Framework 2.0 and it has been widely used in recent times.

This is not the end of the topic as well. With the introduction of Lambda expressions, you can even simplify the declaration of a delegate into an expression. Internally, it works the same way while the code will look like an expression. Let's make the declaration a bit simpler using:

C#
a1.YourCall = e => e += 30;

Here the lambda looks like:

C#
e=> e+= 30

e is basically the integer passed to the delegate and the one that comes after => is the body of the return statement. In this way, the way of writing a short method is very easy and super fast.

Even with the introduction of Lambda expressions like this, Microsoft has already introduced few generic delegates which can define most of the simple methods of regular use.

C#
Action, Action<t>, Action<t1, t2> ..... 

defines can refer to a method which returns void but take arguments as T1, T2 ....

Similarly,

C#
Func<tresult>, Func<t, tresult>, Func<t1, t2, tresult> ..... 

is for referring to methods which return something in the form of TResult and arguments as T1, T2 ....

So instead of writing my own delegate mydelegate, I might better use Func<int, int> to point the same method body. For that, we have to write:

C#
Func<int, int> yourcall = e => e += 30;

Hence practically, you need very less delegate declaration in your code, rather you can instantly use these delegate interfaces instantly while you code. The extension methods introduced with IEnumerable and IQueriable used these delegate to let you pass your own delegate construct on them, such that while it runs over the Enumerable will invoke the logic on each element and based on which it produces the output.

To read more about Linq and Lambda expressions, you can refer to my article here.

Some Depth

Now as you might have a rough idea now about the usage of delegates and how to declare it in your code, it's time to delve deeper into its actuals. I would use my favourite tool Reflector to quick pick about what it writes in IL when we write our own custom delegate for our application.

By nature, a delegate is declared in IL as a class which it derives from System.MulticastDelegate. Following the IL rule, each delegate is a type with abstract implementation of BeginInvoke, EndInvoke and Invoke.

Sample IL for mydelegate declaration

So always keep in mind, delegate is ultimately a Type in IL which has special meaning to hold the reference of method into it.

To demonstrate the use of a delegate, let's suppose we strip down the above code:

C#
static void Main(string[] args)
        {
            Func<int,> myfunc = e => e += 30;

            int result = myfunc(20);
            Console.WriteLine("Result : {0}", result);

            Console.Read();
        }
</int,>

Now if you try to see what it actually writes for you in IL, you would be surprised to see the result.

Hence, from the above tree, you can see, there are a few things more that have been created in addition to the Main method that you have declared.

  1. CS$<>9_CachedAnnonymousMethodDelegate1 is actually a static declaration of the delegate Func<int, int> to the class Program (it is the static member of the class Program).
  2. <Main>b_0(int32): Int32 represents a method that I have declared in our code as anonymous delegate. If you try to look into the code for this method, you will find the same logic that you might have used in your code before as anonymous delegate.
  3. The Main method, assigns the method <Main>b_o(int) to static member delegate and calls Invoke method to invoke the method body.

Hence, from IL, we can conclude, anonymous delegate is not a feature in terms of IL, it's an adjustment made in C# compiler itself to enable it to generate a type based on the delegate we define, but in terms of language perspective, we can eliminate some portion of code easily which will be handled later on by the compiler itself.

Let's test how smart the compiler is, let me introduce a few local variables into the scope.

C#
static void Main(string[] args)
        {
            int x = 20;
            int y = 30;

            int z = 50;

            Func<int,> myfunc = e => e += (x + y);

            int result = myfunc(20);
            Console.WriteLine("Result : {0}", result);

            Console.Read();
        }
</int,>

Now here we intentionally passed two local variables x and y to the delegate myfunc to check how smart the compiler is to detect the variables, as we already know the compiler generates a normal method for every anonymous delegates. Now if you see the IL, surprisingly, you will come up with a completely new type. The compiler generates a class for you and puts each backing field into it as Data member.

Here the <>c_DisplayClass1 represents the type which has been created by the compiler. As in my code, I have used x, and y variable as a part of the delegate, the value of the variables will be created dynamically into the code and hence passed to the method call. The delegate ultimately points to the <Main>b__0 method created within the Type <>c_DisplayClass1. Similarly, to check how smart the C# compiler is, let me create a reference to another method.

C#
static void Main(string[] args)
        {
            int x = 20;
            int y = 30;

            int z = 50;

            Func<int,> myfunc = e => e += (x + y);
            Func<int,> myfunc2 = e => e += (x + z);

            int result = myfunc(20);
            Console.WriteLine("Result : {0}", result);

            Console.Read();
        }

</int,></int,>

Now if you look into the IL, the CompilerGenerated class <>c_DisplayClass1 will also put z into it and also create another method <Main>b__1 into it for 2nd reference.

Smart enough, right.

Notice, there is special meaning on the Type Name. The name inside angular braces represents the name of the method in which the delegate is declared (in our case, it is Main). An arbitrary name is assigned with a numeric value which indicates the index of each method and hence for unique identification.

Summary

Let's point out few facts that we have learnt from the demonstration:

  1. Delegate is a Type derived from System.MulticastDelegate which has a special meaning to refer to a method.
  2. Anonymous delegate as introduced in C# 2.0; is solely a concept introduced in C# compiler itself, and it does not have any special meaning to the MSIL.
  3. C# compilers are smart enough to auto generate Types based on the local references we pass within the delegate we define.

Conclusion

Delegates are very useful while you are about to develop any client - server application or for event based approaches. But delegates most of the times impose compiler generated Types through C# compiler. Hence it is important to keep in mind how the application will behave during actual execution. I hope this post gave you a solid foundation on the so called delegates.

Happy coding!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
President
India India
Did you like his post?

Oh, lets go a bit further to know him better.
Visit his Website : www.abhisheksur.com to know more about Abhishek.

Abhishek also authored a book on .NET 4.5 Features and recommends you to read it, you will learn a lot from it.
http://bit.ly/EXPERTCookBook

Basically he is from India, who loves to explore the .NET world. He loves to code and in his leisure you always find him talking about technical stuffs.

Working as a VP product of APPSeCONNECT, an integration platform of future, he does all sort of innovation around the product.

Have any problem? Write to him in his Forum.

You can also mail him directly to abhi2434@yahoo.com

Want a Coder like him for your project?
Drop him a mail to contact@abhisheksur.com

Visit His Blog

Dotnet Tricks and Tips



Dont forget to vote or share your comments about his Writing

Comments and Discussions

 
GeneralCool!!!! Pin
shakil03040031-Feb-11 0:29
shakil03040031-Feb-11 0:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.