The mechanics of delegates


In the first part of this series, I tried to explain what delegates are in the .NET context. Now, as promised, I’m going to explain the mechanics of delegates in particular:

  1. Declaration of a delegate type
  2. Providing an implementation compatible with the delegate signature. Strictly speaking, this can exist independently of delegates but it is required before the next step can happen.
  3. Instantiation of a delegate
  4. Invocation of a delegate

Declaration of a delegate type

class Person
{
public static void Eats()
{
// Some implementation
}
public static void Says(string message)
{
// Some implementation
}
}

The code above is the same one provided in a previous post and we’ll re-use this later in order to discuss the mechanics of delegates.

If you are familiar with Interfaces in .NET then the following code:

Interface IMyInterface
{
void SomeMethod();
}
view raw gistfile1.cs hosted with ❤ by GitHub

should not be daunting.

In this interface, we are specifying a signature for a method “SomeMethod” which doesn’t take any parameter and doesn’t return any value.

void SomeMethod();

There is absolutely no implementation provided because in an Interface we are merely declaring a contract through the method signature that compatible methods should adhere to.

Likewise, when declaring a delegate, we are declaring a contract and specifying the signature that compatible methods should adhere to. In .NET, this is how we do it:

delegate void PersonEatsDelegate();

If you were to remove the “delegate” keyword, then the signature of “PersonEatsDelegate” is exactly the same as that of “SomeMethod” i.e. any method adhering to the “PersonEatsDelegate” will not take any parameter and return no value.

Just like in the Interface example, there is absolutely no implementation given, just a contract. Hence, it is quite common to hear delegates being explained as being like an Interface with only one method contract, which is exactly what a delegate declaration is. For completeness’s sake, the delegate declaration cannot be in a file of its own but has to exist either in a file where a class or interface is defined.

Providing an implementation compatible with the delegate signature

Since, in the delegate declaration we have provided absolutely no implementation but merely a contract, we now have to provide a handler method implementation which adheres to the signature of the delegate declaration.

If you’ve been able to follow along, then if you go back to the top of this post, you will notice that the “Eat” method of the “Person” class provides one such implementation.

public static void Eats()
{
// Some implementation
}

because it is a method with no parameter and which doesn’t return anything and that matches the “PersonEatsDelegate” delegate type declaration.

Now consider the method “Says” of the Person class:

public static void Says(string message)
{
// Some implementation
}

this method doesn’t match the delegate declaration since it has one parameter.

Instantiation of a delegate

This was actually already given in the first part of this series as:

PersonEatsDelegate personEatsDelegate = Person.Eat;

However, if you were to try and do:

PersonEatsDelegate personEatsDelegate = Person.Says;

you wouldn’t be able to compile the code because the signature of method “Says” doesn’t match the delegate type declaration “PersonEatsDelegate“.

Now in the first part of this series, I tried to emphasise time and again the fact that a delegate is a reference type. The reason I bring this up is because when one instantiates a reference type, one usually uses the “new” keyword and in our two instantiation examples, there is no sight of the “new” keyword. For example, when we instantiate a class we would “new” it up like:

var person = new Person();

So why is this not the case for delegates? Well in actual fact, there is an implicit “newing” up. So when we instantiate the delegate as:

PersonEatsDelegate personEatsDelegate = Person.Eat;

we could also write it as:

PersonEatsDelegate personEatsDelegate = new PersonEatsDelegate(Person.Eat);

The first incarnation is simply the shortened form of the second. However, the latter emphasises the fact that a delegate type is indeed a reference type albeit a special one.

In the first part of this series, I asked the reader to ignore the fact that we are using “Person.Eat” rather than “Person.Eat()” which syntactically might be more familiar when dealing with methods whereby the former might indicate the referencing of an object property. However, during the instantiation  of a delegate we’re assigning (or pointing to) a method to a delegate type. If, we were to call “Person.Eat()”, then the method would actually be invoked and this is not really what we want. What we want is to have a reference to a method which conforms to the signature of the delegate.

Invocation of a delegate

This is the easy part. Now that we’ve instantiated the delegate as:

PersonEatsDelegate personEatsDelegate = Person.Eat;

we invoke it as:

personEatsDelegate();

as a result of which, the method “Eats()” will get executed.

The code given in this section can be found here.

A few words

This section hopefully will have provided a good explanation about the mechanics of delegates. However, it is understandable if the user is still none the wiser as to when to use it but this will be explained in another post in this series.

 

 

Posted in .NET
One comment on “The mechanics of delegates
  1. […] not compile because I’ve omitted important code which I’ll cover when dealing with the mechanics of delegates (declaring, instantiating and invoking). What I’ve shown here is only the instantiation […]

Leave a reply to Delegates | Mapping the territory Cancel reply