Monday, December 3, 2007

Understanding Delegates



In this article we will deal with Delegates in C#. I tried my best to keep this article very simple so that people could understand the basics of delegates.

In simple words when you invoke something on Delegates it Delegates( means hand over) to some one. Delegates acts like a bridge between a method that is invoked and a person responding.

Perhaps you can recall from high-school days that sound travels with Particles. Sound emitted at Point A(Source) reaches Point B (Receiver) with the help of medium. An example of a medium is an interface to travel sound from Point A to Point B. Similary, Delegates are interfaces to pass functionality from one object to another object. You guys may me wondering why I am teaching physics, medium was a perfect example for a Delegate.

It looks like a method Overriding but Delegates concept is much more robust and powerfull than method overriding.

  • A delegate in C# allows you to pass methods of one class to objects of other classes that can call those methods. You can pass method Play (method name) in Class A, wrapped in a delegate, to class B and Class B will be able to call method Play in class A.
  • Delegates in C# are objects which points towards a function which matches its signature. Delegates are reference type used to encapsulate a method with a specific signature.
  • A delegate instance encapsulates a static or an instance method. Delegates are roughly similar to function pointers in C++; however, delegates are type-safe and secure.
  • You can pass both static and instance methods.
  • A delegate represents a class.
  • A delegate is type-safe.
  • You can combine multiple delegates into a single delegate.
  • You can use delegates both for static and instance methods.
  • You can define delegates inside or outside of classes.
  • You can use delegates in asynchronous-style programming.
  • Delegates are often used in event-based programming, such as publish/subscribe.

    The delegate declaration takes the form:

    [attributes] [modifiers] delegate result-type identifier ([formal-parameters]);
    attributes (Optional)

    The allowed modifiers are new and the four access modifiers.
    result-type

    The result type, which matches the return type of the method.

    identifier

    The delegate name.

    formal-parameters (Optional)

    Parameter list. If a parameter is a pointer, the delegate must be declared with the unsafe modifier. Delegates are the basis for events.

    Functionality of Delegates can be accomplished in four steps.

    1 Declare a delegate object with a signature that exactly matches the method signature that you are trying to encapsulate.

    2. Define all the methods whose signatures match the signature of the delegate object that you have defined in step 1.

    3. Create delegate object and plug in the methods that you want to encapsulate.

    4. Call the encapsulated methods through the delegate object.

    following C# code shows the above four steps implemented using one delegate and two classes.

    using System;
    namespace DelgateDemo
    {
    // Define a delegate
    public delegate void MyDelegate(int a,int b);
    class MyDelegateImp
    {
    // You need this function to construct your delegate object
    // delegateAdd is a non static method
    public void delegateAdd(int i , int j)
    {
    int k=i+j;
    Console.WriteLine("This is delegateAdd
    method Addition of numbers {0}",k);
    }
    // You need this function to construct your delegate object
    // delegateSub is a non static method
    public void delegateSub(int i, int j)
    {
    int k=i-j;
    Console.WriteLine("This is delegateSub
    method Subtraction of numbers {0}",k);
    }
    // You need this function to construct your delegate object
    // delegateMul is a static method
    public static void delegateMul(int i , int j)
    {
    int k=i*j;
    Console.WriteLine("This is delegateMul
    method Multiplication of numbers {0}",k);
    }
    }
    class Class1
    {
    static void Main(string[] args)
    {
    // Instantiating a simple delegate Implementation class
    MyDelegateImp Obj = new MyDelegateImp();
    // Instantiating a simple delegate delegateAdd this
    // is Instance method in Implementation Class
    MyDelegate DelAdd= new MyDelegate(Obj.delegateAdd );
    // Calling a simple delegate delegateAdd
    Console.WriteLine("invoking instance method delegateAdd");
    DelAdd(9,9);
    // Instantiating a simple delegate delegateSub this
    // is Instance method in Implementation Class
    MyDelegate DelSub= new MyDelegate(Obj.delegateSub );
    // Calling a simple delegate delegateSub
    Console.WriteLine ("invoking instance method delegateSub");
    DelSub(18,9);
    // Instantiating a simple delegate delegateMul this is
    // Static method in Implementation Class
    MyDelegate DelStatic = new MyDelegate(MyDelegateImp.delegateMul );
    Console.WriteLine ("invoking static method delegateMul ");
    DelStatic(9,9);
    // Combining delegates
    MyDelegate CompDel=(MyDelegate)Delegate.Combine(DelAdd,DelSub);
    //calling a composite delegate
    Console.WriteLine("Combining Delegates OutPut");
    CompDel(180,90);
    // you can also remove delegates
    // delegates are immutable
    MyDelegate ResDel=(MyDelegate)Delegate.Remove(CompDel,DelSub);
    Console.Write("Removing a Delegate from Combining Delegates Output ");
    ResDel(45,54);
    // operator overloading
    MyDelegate OperDel=DelAdd+DelSub;
    Console.WriteLine ("Operator OverLoading Delegates OutPut");
    OperDel(360,180);
    Console.ReadLine();
    }
    }
    }