[C#] Delegates

Have you ever heard of function pointers? If you have studied C or C++, you know what the pointer is. Just like the pointer to a value or an object, there is the pointer to a function.

The function pointer has a reference to the function’s entry point so that you can invoke the function not by a function name but by the pointer variable. 

A function pointer is very useful when you use the callback feature. JavaScript uses it very often. For example, when you make a asynchronous call to the server, you pass the handler function’s pointer with the request call. When the server is ready to respond, the server just calls the function using the function pointer.

In C#, this functionality is accomplished by delegates. A “delegate” is an object that points to another mothod (both static and instance). It manages the address of (or a reference to) a method, a list of arguments, and a return value.

 

1. Declaring a Delegate Type

The “delegate” keyword is used to declare a delegate type in C#. The delegate definition looks like a definition of a method. Once a delegate type is defined, you can create an instance of the delegate type and use it to point to a method that has the same signature as the delegate type.

Internally a delegate is a sealed class derived from the “System.MulticastDelegate” class, which is also derived from the “System.Delegate” class.

Let’s create a delete type which points to any method which gets 3 int parameters and returns int value.

public delegate int DoSomethingWithInt(int x, int y, int z);

 

2. Using a Delegate

Defining a delegate is like defining a class. Until you create an instance of it, it won’t do anything.

public class IntFun
{
  public static int GetTotal(int x, int y, int z)
  {
    return (int)(x + y + z);
  }
  public static int GetAverage(int x, int y, int z)
  {
    return (int)((x + y + z) / 3);
  }
}

I wanted to use the “DoSomethingWithInt” delegate to point to the “GetTotal()” or “GetAverage()” method. To do this, you need to create an delegate object.

DoSomethingWithInt fp = new DoSomethingWithInt(IntFun.GetTotal);
DoSomethingWithInt fp1 = new DoSomethingWithInt(IntFun.GetAverage);

Or you can create delegate object implicitly.

DoSomethingWithInt fp = IntFun.GetTotal;
DoSomethingWithInt fp1 = IntFun.GetAverage;

Now the final step!!!

How can we call the method from a delegate object. Internally a delegate object has the “Invoke()” method. But in C#, you do not call the “Invoke()” method directly (You can do it if you want). You can use a name of a delegate object as it is a method name.

Console.WriteLine("Total = {0}", fp(10, 20, 30));
Console.WriteLine("Average = {0}", fp1(10, 20, 30));

Isn’t it cool?

 

3. Invoking Multiple Methods using One Delegate Object

Delegates can invoke multiple methods through a single call from a delegate object. This feature is called “Multicasting” and makes it possible to add multiple handlers to an event.

The “+=” and “-=” operators are overriden for delegates to add or remove a method into/from a delegate object.

public delegate void Greet();
public class GreetFun
{
  public void Hello()
  {
    Console.WriteLine("Hello, How are you doing?");
  }
  public void Bye()
  {
    Console.WriteLine("Bye.");
  }
}

GreetFun greet = new GreetFun();
Greet fp = new Greet(greet.Hello); // you can point to an instance method too.
fp += greet.Bye;  // call Hello() and Bye()

 

4. Looking inside the Delegate Object

You can use the following code to see the list of methods that the delegate holds.

public static void InvestigateDelegate(Delegate dObj)
{
  foreach (Delegate d in dObj.GetInvocationList())
  {
    Console.WriteLine("Type = {0}, Method = {1}", d.Target, d.Method);
  }
}

 

5. Generic Delegates

You can also create a generic delegate.

public delegate T Adder<T>(T x, T y);

public class GenericFun
{
  public static int AddInt(int x, int y)
  {
    return (x + y);
  }
  public static string AddNumber(string x, string y)
  {
    double a = Double.Parse(x);
    double b = Double.Parse(y);
    return (a + b).ToString();
  }
}

Adder<int> fp = new Adder<int>(GenericFun.AddInt);
Adder<string> fp1 = new Adder<string>(GenericFun.AddNumber);

Console.WriteLine("2 + 3 = {0}", fp(2, 3));  // 5
Console.WriteLine("1.4 + 4.7 = {0}", fp1("1.4", "4.7"));  // 6.1

 

6. Anonymous Methods

When you add a method to a delegate, you need to define the method first. For your convienence, C# 2.0 provides another construct to declare a method without a name. The “delegate” keyword is used to declare an anonymous method.

The syntax of an anonymous method is simple:

delegate (parameters) { method body }

The only thing you need to care is that you cannot specify a return type. Just make sure you return the right type in the method body.

The anonymous method works with generic types too.

public delegate T Adder<T>(T x, T y);

public static void TestAnonymous()
{
  Adder<int> fp = new Adder<int>(delegate(int x, int y) { return (x + y); });
  Console.WriteLine("2 + 3 = {0}", fp(2, 3));
}

 

7. Lambda Expressions

As the introduction of “LINQ” in C#, the anonymous method became more important than before.

C# introduces the short syntax to the anonymous method. Lambda Expressions use the lambda operator =>“. The left side of the lambda operator specifies the input parameters and the right side holds the expression or statement block.

  • Expression Lambdas

(input parameters) => expression

(x,y) => x == y
(string s, int x) => (s.Length <= x)

If you do not specify the type of a parameter, the compiler will infer the type.

  • Statement Lambdas

(input parameters) => {statement;}

s => { Console.WriteLine(s); }

Let’s rewrite the generic anonymous method using a Lambda operator.

public delegate T Adder<T>(T x, T y);

public static void TestLambda()
{
  Adder<int> fp = new Adder<int>((x, y) => { return (x + y); } );
  Console.WriteLine("2 + 3 = {0}", fp(2, 3));
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s