Delegates




Delegates



Purpose of this post is to take baby steps towards understanding delegates in .Net by using simple example and gradually proceed to more complex scenarios.

Definition

A delegate in C# is similar to a function pointer in C or C++. Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object. The delegate object can then be passed to code which can call the referenced method, without having to know at compile time which method will be invoked. Unlike function pointers in C or C++, delegates are object-oriented, type-safe, and secure. [msdn]

Where to use Delegates

If we look at the prime use of delegates its mostly used for implementing events and the call-back methods. 

Which Namespace has them

All delegates are implicitly derived from the System.Delegate class.

Types of Delegates

Delegates are three types:
  • Single Delegate
  • Multicast Delegate
  • Generic Delegate

Single Delegate

Understand Single Delegate with simple example

Perform following steps to get up to a point where you have the program set up before we dive deep and understand what is happening:
  • Make a console project in Visual Studio
  • In the default project add a new class SimpleCalculator.cs, use the following code
    /// <summary>
    /// Simple Calculator performing Addition, Subtraction, Multiplication and Division
    /// </summary>
    public class SimpleCalculator
    {
        /// <summary>
        /// Add Numbers
        /// </summary>
        /// <param name="num1">Number 1</param>
        /// <param name="num2">Number 2</param>
        /// <returns>Addition of num1 and num2</returns>
        public static int Add(int num1,int num2)
        {
            return num1 + num2;
        }
        /// <summary>
        /// Subtract Numbers
        /// </summary>
        /// <param name="num1">Number 1</param>
        /// <param name="num2">Number 2</param>
        /// <returns>Substration of num1 and num2</returns>
        public static int Subtract(int num1, int num2)
        {
            return num1 - num2;
        }
        /// <summary>
        /// Multiply Numbers
        /// </summary>
        /// <param name="num1">Number 1</param>
        /// <param name="num2">Number 2</param>
        /// <returns>Multiplication of num1 and num2</returns>
        public static int Multiply(int num1, int num2)
        {
            return num1 * num2;
        }
        /// <summary>
        /// Divide Numbers
        /// </summary>
        /// <param name="num1">Number 1</param>
        /// <param name="num2">Number 2</param>
        /// <returns>Division of num1 and num2</returns>
        public static int Divide(int num1, int num2)
        {
            return num1 / num2;

        }
   }  
  • Replace your program.cs class code with following code:
    class Program
    {
        delegate int SimpleCalculatorDelegate(int num1,int num2);
        static void Main(string[] args)
        {
            Single();
        }

static void Single()
        {
            var scdAdd = new SimpleCalculatorDelegate(SimpleCalculator.Add);
            var scdSubtract = new SimpleCalculatorDelegate(SimpleCalculator.Subtract);
            var scdMultiply = new SimpleCalculatorDelegate(SimpleCalculator.Multiply);
            var scdDivide = new SimpleCalculatorDelegate(SimpleCalculator.Divide);

            int num1 = 10;
            int num2 = 5;

            Console.WriteLine("Running Calculations with Single delegate  using {0},{1}: ", num1, num2);

            Console.WriteLine("Add({0}+{1}): {2}", num1, num2, scdAdd(num1, num2));
            Console.WriteLine("Subtract({0}-{1}): {2}", num1, num2, scdSubtract(num1, num2));
            Console.WriteLine("Multiply({0}*{1}): {2}", num1, num2, scdMultiply(num1, num2));
            Console.WriteLine("Divide({0}/{1}): {2}", num1, num2, scdDivide(num1, num2));

            Console.ReadLine();

        }
    }


  • You project should be building fine at this point if you have any problems compiling your code leave me a message I will get back to you as soon as possible.
  • Running the application will produce the following output:


Explanation

Single delegate can only invoke a single method in one call simply putting SimpleCalculatorDelegate can only invoke Add or Delete or Multiply or Divide in one call.

Above example has a simple class with simple methods defined in that, purpose SimpleCalculator class is to perform calculations nothing more is expected from that. Two numbers are passed to all the methods defined in the class and in return you get one number back as a result.

By now we started to note some symmetry building up there, each method has two arguments and one result; pretty straight forward up to this point.

As we know in simple words delegate is a representative and its job is to represent something. C# delegate has some structure assigned to it.

Lets try to find the structure so that we can make sense out of it:
  • Delegate should have same number of arguments as the function we are trying to encapsulate.
  • Delegate should have same return type as the function we are trying to encapsulate.
In our case we defined:
delegate int SimpleCalculatorDelegate(int num1,int num2);

which is exactly same in signature as:
int Add(int num1,int num2)
int Subtract(int num1, int num2)
int Multiply(int num1, int num2) 
int Divide(int num1, int num2)

One note to make here is your method or function can be Static or NonStatic, delegate has no problem representing it.

Next we will see the declaration part of it:
var scdAdd = new SimpleCalculatorDelegate(SimpleCalculator.Add);
var scdSubtract = new SimpleCalculatorDelegate(SimpleCalculator.Subtract);
var scdMultiply = new SimpleCalculatorDelegate(SimpleCalculator.Multiply);
var scdDivide = new SimpleCalculatorDelegate(SimpleCalculator.Divide);

Here we created object of our delegate and passed in the method we want it to represent, since method and delegate have similar signature; delegate will represent the method happily!

Next we will see the usage part of it or calling part of it:
Console.WriteLine("Add({0}+{1}): {2}", num1, num2, scdAdd(num1, num2));
Console.WriteLine("Subtract({0}-{1}): {2}", num1, num2, scdSubtract(num1, num2));
Console.WriteLine("Multiply({0}*{1}): {2}", num1, num2, scdMultiply(num1, num2));
Console.WriteLine("Divide({0}/{1}): {2}", num1, num2, scdDivide(num1, num2));

When we defined our delegate objects and passed methods to represent to it delegate know in which object which method it is representing. So when we say scdAdd(num1, num2) it will call the Add method and pass on the arguments and receive the output and pass it back.


By so far I have made an attempt to explain a delegate in easiest way I can.

--------------------------------------------------------------------------------------------------------------------------

Multicast Delegate

Understand Multicast Delegate with simple example

Perform following steps to get up to a point where you have the program set up before we dive deep and understand what is happening:
  • Make a console project in Visual Studio
  • In the default project add a new class SimpleCalculator.cs, use the following code
    /// <summary>
    /// Simple Calculator performing Addition, Subtraction, Multiplication and Division
    /// </summary>
    public class SimpleCalculator
    {
        /// <summary>
        /// Add Numbers
        /// </summary>
        /// <param name="num1">Number 1</param>
        /// <param name="num2">Number 2</param>
        /// <returns>Addition of num1 and num2</returns>
        public static int Add(int num1,int num2)
        {
            return num1 + num2;
        }
        /// <summary>
        /// Subtract Numbers
        /// </summary>
        /// <param name="num1">Number 1</param>
        /// <param name="num2">Number 2</param>
        /// <returns>Substration of num1 and num2</returns>
        public static int Subtract(int num1, int num2)
        {
            return num1 - num2;
        }
        /// <summary>
        /// Multiply Numbers
        /// </summary>
        /// <param name="num1">Number 1</param>
        /// <param name="num2">Number 2</param>
        /// <returns>Multiplication of num1 and num2</returns>
        public static int Multiply(int num1, int num2)
        {
            return num1 * num2;
        }
        /// <summary>
        /// Divide Numbers
        /// </summary>
        /// <param name="num1">Number 1</param>
        /// <param name="num2">Number 2</param>
        /// <returns>Division of num1 and num2</returns>
        public static int Divide(int num1, int num2)
        {
            return num1 / num2;

        }
   }  
  • Replace your program.cs class code with following code:
    class Program
    {
        delegate int SimpleCalculatorDelegate(int num1,int num2);
        static void Main(string[] args)
        {
            Multicast();
        }
 private static void Multicast()
        {
            var scdAdd = new SimpleCalculatorDelegate(SimpleCalculator.Add);
            var scdSubtract = new SimpleCalculatorDelegate(SimpleCalculator.Subtract);
            var scdMultiply = new SimpleCalculatorDelegate(SimpleCalculator.Multiply);
            var scdDivide = new SimpleCalculatorDelegate(SimpleCalculator.Divide);

            int num1 = 10;
            int num2 = 5;


            var scdAddSubtract = (SimpleCalculatorDelegate)Delegate.Combine(scdAdd, scdSubtract);
            var scdMultiplyDivide = (SimpleCalculatorDelegate)Delegate.Combine(scdMultiply, scdDivide);



            Console.WriteLine("\r\nRunning Calculations with Multicast delegate(Using Simple Invoke) using {0},{1}: ", num1, num2);

            Console.WriteLine("Run Add and Subtract with {0},{1}: {2}", num1, num2, scdAddSubtract(num1,num2));
            Console.WriteLine("Run Multiply and Divide with {0},{1}: {2}", num1, num2, scdMultiplyDivide(num1, num2));
         
         
            Console.Write("\r\nRunning Calculations with Multicast delegate(Using Invocation List) using {0},{1}: ", num1, num2);

            Console.Write("Run Add and Subtract with {0},{1}: ", num1, num2);
            scdAddSubtract.GetInvocationList().Select(x => (int)x.DynamicInvoke(num1, num2)).ToList().ForEach(x => Console.Write("  " + x + " "));

            Console.Write("\r\nRun Multiply and Divide with {0},{1}: ", num1, num2);
            scdMultiplyDivide.GetInvocationList().Select(x => (int)x.DynamicInvoke(num1, num2)).ToList().ForEach(x => Console.Write("  " + x + " "));

         
            Console.ReadLine();

        }
}

  • You project should be building fine at this point if you have any problems compiling your code leave me a message I will get back to you as soon as possible.
  • Running the application will produce the following output:

Explanation

With multicast delegate you can combine functionality of more than one delegates.

var scdAddSubtract = (SimpleCalculatorDelegate)Delegate.Combine(scdAdd, scdSubtract);

scdAddSubrtact has combined scdAdd and acdSubtract i.e. calling scdAddSubrtact will run both of them. You need to use invocation list as shown above if you want the data from all the subdelegates else you will only get the data from the one which executed the last. Please refer to the code and output above.

--------------------------------------------------------------------------------------------------------------------------

Generic Delegate

Understand Generic Delegate with simple example

Work in Progress, please check back later

Comments

Popular posts from this blog

Azure - Manage Blob Storage - Part #7 - Add Metadata to an Existing Container using C#

Azure - Manage Blob Storage - Part #5 - Create Folder Structure and upload a file to folder using an Existing Container using C#

Algorithm - Breadth First Search(BFS) - Python(3)