Delegates are not just function pointers with a fancy name, they are a huge leap over C++’s function pointers. Unlike unmanaged languages, .NET enforces type safety for its delegates. Good, because pointers are too scary to be tolerated in .NET’s perfect world, where there are no memory leaks and all a developer has to worry about it is his own application code. Ok that doesn’t always happen, but 9 times out of 10 isn’t all that bad.
Lets look at a simple example. Consider a delegate type Notify which writes an error message to various logs. It returns void and takes in a string parameter which is the message. Now there is a class DelegateSample which has the various methods to the log the error.
//This is our delegate type public delegate void Notify(string message); class DelegateSample { public void NotifyToConsole(string _notificationMessage){ Console.WriteLine("Notifying Console "+_notificationMessage); } public void NotifyToEventLog(string _notificationMessage){ //Write an Entry in the Event Log Console.WriteLine("Entry has been written in the event log as " + _notificationMessage); } public void NotifyDatabase(string _notificationMessage){ //Log in some database table Console.WriteLine("Entry has been written to the DB as " + _notificationMessage); } }
Notice all these methods have a same Signature. This part is enforced in delegates. All the methods necessarily must be of the same return type and take in the same type arguments. Lets call this class in our main method. First we declare three delegate objects for our three functions. Then we use the += operators to chain the delegates. Chaining is a very useful technique to call multiple functions using the same delegate object. So when we call the first object, all of the others chained to it get called in the same sequence.
static void Main(string[] args) { Notify _notifyConsole = new Notify(new DelegateSample().NotifyToConsole); Notify _notifyEventLog = new Notify(new DelegateSample().NotifyToEventLog); Notify _notifyDataBase = new Notify(new DelegateSample().NotifyDatabase); _notifyConsole += _notifyEventLog; _notifyConsole += _notifyDataBase; _notifyConsole("Hello"); }
So how does this chaining work? If we reflect on the assembly we see that the one line Notify delegate has been transformed magically into a class which Derives from MulticastDelegate, which in turn derives from the abstract class Delegate. 
All the delegate’s work is done by these two classes. The += method is just compiler eye candy, where the actual call is done to the static method Delegate.Combine which takes in two Delegates and returns a Delegate which is cast to the MulticastDelegate type. Delegate.Combine first checks whether one of the two arguments is null, if so it simply returns the other and thats the end of it, If not it calls the CombineImpl method which is virtual so it goes down and calls the same method in the MulticastDelegate class which we actually passed to it.
This method is called on the instance of one of the delegates and the other one is passed as an argument, so the first thing the combineImpl does is to get the invocationLists of both delegates
MulticastDelegate dFollow = (MulticastDelegate)follow; Object[] resultList; int followCount = 1; Object[] followList = dFollow._invocationList as Object[]; if (followList != null) followCount = (int)dFollow._invocationCount; int resultCount; Object[] invocationList = _invocationList as Object[];
After this both the invocation list and follow list are combined to form the result list. Once its done, both the result list and the count are passed to a method called NewMulticastDelegate.
This method creates a Multicastdelegate of the same type as the object which it is called on. Thats done by a method called InternalAllocLike, which is an internalCall. Internal call methods are not written in the BCL but they are implemented in unmanaged code. A good place would be to look for would be the ecall.cpp file where the exact class for the function is mentioned. In our case it is Comdelegate.cpp. So the new Object which is of NotifyType has all its properties like the target, invocation list and count are set here and the final combined deleagate is returned which is assigned to the _notifyConsole. The older delegate object _notifyEventLog which is discarded now and its invocation list is added to the _notifyConsole.
So when we call Invoke on the delegate object, the code iterates through its invocation list and calls each target one by one resulting in the whole chain of methods being executed. Chaining is extremely useful in many practical scenarios. Consider events. When we use the new EventHandler to hook a method to a button’s click event, we are actually adding an entry for the method in the delegates invocation list. So when the Click is invoked, all its subscribers get executed.



