Delegate to Lambda - Part 2

Welcome to the second part of the series called - "Delegate to Lambda". I call it a series because delegate is one of the most important and huge aspects of using and understanding C#. In my opinion it would not be a good idea to discuss the whole thing in one post. So, I decided to break the topic into different parts and describe from the very begining till the end.

Important features of C# like LINQ and event rely on delegate. That is why, it's so important to have a clear idea about delegate. In my previous post I have tried a little bit to scratch the surface of delegate. In doing so, I have written code like this,

MyDelegate del_02 = new MyDelegate(Foo); // Where Foo is a static method

Well, we don't have to use the 'new' key word each time we want to instantiate a new instance of MyDelegate. It is possible to simplify the code like the following.

MyDelegate del_02 = Foo;

This is possible because, by the time we mentioned "MyDelegate del_02 = ...", our compiler is smart enough to figure it out that the right side of the assignment must have to be a method and the method must match the signature of MyDelegate. In our case method 'Foo()' is a valid candidate because it takes no argument and returns void.

private static void Foo()
        {
            Console.WriteLine("Foo();");
        }

So, we can assign (or refer to) a compatible or matched method name to a delegate instance.

Invoking Delegate

A delegate is an object instance which is a reference to a function (a function is called method in C#). As it is such, we can use delegate instances as method parameters and then invoke them inside the method. That means, we can call an entire method inside a method. Wow! Let's see an example.

Say we have a method called 'InvokeMyDelegate' that takes a MyDelegate as a parameter. We can now invoke the delegate like following,

private static void  InvokeMyDelegate(MyDelegate del)
    {
        del();
    }

Now, when we are using or calling our InvokeMyDelegate() method, compiler already knows that our method takes a MyDelegate instance as a argument. Compiler also knows the signature of MyDelegate - taking no parameter and returning void. And, this signature matches perfectly to our 'Foo()' method. So, we can write code like this,

MyDelegate del_02 = Foo;
InvokeMyDelegate(del_02);

But, instead of passing a MyDelegate instance as an argument we can pass the 'Foo()' method while calling our 'InvokeMyMethod()' and completely discard the line "MyDelegate del = Foo;". Because, earlier we saw that, we can refer to a matched method name instead of creating new instance of the delegate.

So, in short we can pass matching method names in place of delegate instances to avoid creating new delegate instances. In our case it looks like the following.

InvokeMyDelegate(Foo);

What's the point

So, what's the point of having a method and passing another method as it's argument? Well, for now it will help us to explore two of the important properties of a delegate instance. First one is "Target" means which object instance the matched method to invoke upon and second one is "Method" means which matched method to invoke. In our case we can write something like the following snippet

private static void InvokeMyDelegate(MyDelegate del)
       {
           var invokationList = del.GetInvocationList();
 
           foreach (var invoker in invokationList)
           {
               const string target = "Object to invoke the method upon (Target): ";
               Console.WriteLine(invoker.Target == null?
                                   target + "Static Method" :
                                   target + invoker.Target);
               Console.WriteLine("\t Method to invoke: " + invoker.Method);
           }
       }

These two properties will also help us to understand better when we will talk about "event" and "closure". To be continued: Delegate To Lambda - Part 3 

May 11, 2014
Jahan Sarwar