Saturday, December 15, 2012

Delegates basics in .NET


Lets try to understand the concept behind delegate using following example -
 public class Program
{
    public delegate object myDelegate(B a);
    public static myDelegate globalDelegate = new myDelegate(someMethod1);
    static void Main(string[] args)
    {
        myDelegate md = new myDelegate(someMethod1);
        md.Invoke(new B());          
        myDelegate md2 = new myDelegate(someMethod2);
        md2.Invoke(new B());          
    }
    static string someMethod2(B b)
    {
        return b.ToString();
    }
    private static string someMethod1(A a)
    {
        return a.ToString();
    }     
}
public static class outer
{
    public static void test()
    {
        Program.globalDelegate.Invoke(new B());
    }
}

 public class A { }
 public class B : A { }


1) Delegate are like function pointers in C.

2) Delegate indicates the signature of callback method. In the  above example i have defined delegate which takes type B as input and returns object. This delegate can be used to create a wrapper(pointer) for any method which takes B(or its base ) type as an argument and returns object(or its derived types).

 3) Its possible to access private method defined in one class using delegate in another class. In above case if you see we have a public delegate object globalDelegate which is pointing to a private method. But we have invoked that method from an outer class using that delegate. It doesn't mean that using delegate we have any security violation for one type to have code that calls another type's private member as long as the delegate  object created by code that has ample accessibility.

4) Covariance and contra-variance in Delegates -
Both c# and CLR allows covariance and contra-variance of reference(and only reference) types when binding a method to a delegate.
Covariance - a method can return a type that is derived from delegates't return type
Contra-variance  - a method can take a parameter that is base of the delegate's parameter type.
In the above code the return type the myDelegate is expecting is object. As per covariance we can return anything derived from object(only reference type), in current case we are returning string.
Moreover if you see the input parameter myDelegate is expecting is of type B. As per Contra-variance we can use this Delegate for anymethod which is expecting any type which is base for type B(current scenario it is A) as input parameter.

5) If you check the IL generate while using delegate, you will find that the delegate we define, compile creates a class out of it, which has 4 methods constructor, Invoke,BeginInvoke and EndInvoke. This class inherits from System.MulticastDelegate which is derived from system.delegate which itself derived from system.Object.

6) All the delegates inherit from MulticastDelegate, hence they inherit all the proerpties methods. There are 3 most important non-public fields which are important to understand -
_target - for static method delegate its null, else its the object reference on which callback method is going to get execute.
_methodPrt-  internal integer which itentifies which method need to execute.
_invocationList - for normal delegates its null, but when we are talking about chain of delegates, then this is the array which hase pointer to every delegate added into chain.
Here is the diagram which shows the different between static and instance level delegate -

7) Combine - We have combine method available in delegate, which can be used to attached multiple delegate and execute them on any event. The combine method makes use of invocationList to keep the list of delegate and execute them one after another.