Well, at 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 every people in .NET language must 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 you to show a code :
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 reference to a method which can point to a method which have 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 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 have lots 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 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 wants 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 a1.YourMethod = Program.CallMe to
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. Lets make the declaration a bit simpler using :
a1.YourCall = e => e += 30;
Here the lambda looks like
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.
Action, Action<t>, Action<t1, t2> .....
defines can refer to a method which returns void but take arguments as T1, T2 ....
Similarly,
Func<tresult>, Func<t, tresult>, Func<t1, t2, tresult> .....
is for referring to methods which returns 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 :
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 expression 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, its 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 have special meaning to hold the reference of method into it.
To demonstrate the use of a delegate lets suppose we strip down short the above code :
static void Main(string[] args) { Func<int, int> myfunc = e => e += 30; int result = myfunc(20); Console.WriteLine("Result : {0}", result); Console.Read(); }
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 is few things more have been created in addition to the Main method that you have declared.
- 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).
<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.- The Main method, assigns the method <Main>b_o(int) to static member delegate and calls Invoke method to invoke the method body
Hence, we from IL we can conclude, anonymous delegate is not a feature in terms of IL, its 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.
Lets test how smart the compiler is, let me introduce few local variables into the scope.
static void Main(string[] args) { int x = 20; int y = 30; int z = 50; Func<int, int> myfunc = e => e += (x + y); int result = myfunc(20); Console.WriteLine("Result : {0}", result); Console.Read(); }
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 is 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.
static void Main(string[] args) { int x = 20; int y = 30; int z = 50; Func<int, int> myfunc = e => e += (x + y); Func<int, int> myfunc2 = e => e += (x + z); int result = myfunc(20); Console.WriteLine("Result : {0}", result); Console.Read(); }
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
Lets point out few facts that we have learnt from the demonstration :
- Delegate is a Type derived from System.MulticastDelegate which has a special meaning to refer to a method.
- 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.
- 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.
Nice post!
ReplyDeleteI can't wait for more intereesting posts! When will you update your interesting website?
ReplyDelete@Anonymous
ReplyDeleteStay in touch with Twitter to get updates. I am writing Internals on Extension method very soon.
:)