Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Beginner's Guide to Delegates

0.00/5 (No votes)
29 Mar 2006 1  
An article on delegates in .NET.

Introduction

In this article, I've covered a brief introduction about delegates. This can be a good 'Beginner's Guide' to delegates.

Background

Here, I assume you have a basic knowledge of function pointers. Because, in the introductory part, I compare delegates with function pointers. For basic ideas on function pointers, please refer this link.

Simple Delegate

A delegate is very much like a C/C++ 'function pointer' or a 'typedef that represents the address of a function'. In C/C++, the address of a function is just a memory address. The C/C++ function pointer holds only the address of a function. This address doesn't carry any additional information, such as the number of parameters expected by the function, types of parameters it takes etc. In fact, this all makes a function pointer type unsafe. Traditionally, calling a function by its address depends on the language supporting the function pointers. And function pointers are inherently dangerous.

Delegates add a safety to the idea of traditional function pointers. The .NET framework has added the bonus of providing a type-safe mechanism called delegates. They follow a Trust-But-Verify model, with automatic verification of the signature by the compiler. Unlike function pointers however, delegates are object-oriented, type-safe, and secured. In short, a delegate is a data structure that refers to a static method or to an object instance, and an instance method of that object. When the delegate references an instance method, it stores not only a reference to the method entry point, but also a reference to the object instance for which to invoke the method.

In VB.NET, we define a delegate using the 'Delegate' keyword. E.g.:

'Defining the delegate 

Public Delegate Sub GreetingDelegate(ByVal MsgString As String)

This does not declare the delegate, it defines it. With this line, we tell the compiler to create a new class called 'GreetingDelegate' that inherits from 'System.Delegate' (the compiler does it automatically for you). This line is equivalent to writing the following code in C/C++:

typedef void (*GreetingDelegate) (char *);

This delegate is only capable of calling a method that takes a String parameter and return nothing. A delegate cares only about the signature of the method you are encapsulating inside of it. So, the function we encapsulate in this delegate (with the appropriate signature) can be invoked safely using this delegate.

Here, I have written two different functions in VB.NET:

Public Sub GoodMoring(ByVal YourName As String)
    Console.WriteLine("Good Morning " + YourName + " !")
End Sub

Public Sub GoodNight(ByVal YourName As String)
    Console.WriteLine("Good Night " + YourName + " !")
End Sub

Now, inside Sub Main, we can create an instance of the delegate, and can assign the address of a function to the delegate. This is done using the AddressOf keyword as follows:

'Instantiating the delegate

Dim MyGreeting As GreetingDelegate

'Here we assign the address of the function we wish to encapsulate

'to the delegate


Console.WriteLine("Adding 'GoodMoring' Reference To A Delegate...")
MyGreeting = AddressOf GoodMoring

Once we assign an address to a delegate, we can use the Invoke method to call the function encapsulated in the delegate.

'Invoking the delegate

Console.WriteLine("Invoking Delegate...")
MyGreeting.Invoke("Mallinath")

Because a delegate cares only about the signature of the method you are encapsulating inside it, we can make it refer to another method also. E.g.:

'Assigning the address of the another function to the same delegate

Console.WriteLine()
Console.WriteLine("Making Existing Delegate To Point To Another Fuction...")
Console.WriteLine("Replacing With Goodnight Reference...")
MyGreeting = New GreetingDelegate(AddressOf Goodnight)

'Another way of invoking the delegate.

Console.WriteLine("Invoking Delegate...")
MyGreeting("Mallinath")

Surprised? Did I forget to put Invoke() there? No! Actually, you don't need to use Invoke(), you can just use the delegate as a proxy for the method.

If you try to assign the address of a method or function not matching the delegate declaration, you'll get a compiler error. Try the following code by putting it in the downloaded source code:

'your existing code goes over here

'add these following lines 

Public Sub BadGreets()
    Console.WriteLine("Wishing You Bad Greetings !")
End Sub

Sub Main()
    'your existing code goes over here

    'add these following lines and try

    MyGreeting = AddressOf BadGreets
    MyGreeting.Invoke("Mallinath")
End Sub

Multicast Delegates

Coming to multicast delegates, these are delegates which are capable of pointing to multiple functions of the same signature. The System.Delegate type maintains a linked list that is used to hold the references to the functions to be invoked by the delegate. This linked list is called as the Invocation List. The delegate class provides a shared member function called Combine(), which adds a reference of specified function to the invocation list.

To demonstrate a multicast delegate, I've added a new function 'GoodEvening', along with the earlier two, to the MulticastDelegate sample program. And I have created separate delegates for each one of the earlier functions.

Public Delegate Sub GreetingDelegate(ByVal MsgString As String)

Public Sub GoodMorning(ByVal YourName As String)
    Console.WriteLine("Good Morning " + YourName + " !")
End Sub

Public Sub Goodnight(ByVal YourName As String)
    Console.WriteLine("Good Night " + YourName + " !")
End Sub

Public Sub GoodEvening(ByVal YourName As String)
    Console.WriteLine("Good Evening " + YourName + " !")
End Sub

In Sub Main, I've instantiated them as:

Dim MorningGreets As GreetingDelegate
Dim EveningGreets As GreetingDelegate

MorningGreets = AddressOf GoodMorning
EveningGreets = New GreetingDelegate(AddressOf GoodEvening)

To illustrate the multicast delegate, I've combined both the delegates into a single delegate, using the Combine() method as:

Console.WriteLine("Adding 'MorningGreets' And" & _
        " 'EveningGreets' References To A Delegate...")
Dim AllGreets As GreetingDelegate = _
        [Delegate].Combine(MorningGreets, EveningGreets)

Combine() returns a new delegate with the merged invocation list of the function references of the specified delegates. Here, we can add one more function reference to the existing delegate as:

Console.WriteLine("Adding Another" & _ 
    " References To Existing Delegate...")
AllGreets = [Delegate].Combine(AllGreets, _
    New GreetingDelegate(AddressOf Goodnight))

As I wrote, the delegate definition line tells the compiler to create a new class inheriting from the System.Delegate type:

Dim NightGreets As GreetingDelegate =  AddressOf Goodnight

This is equivalent to:

Dim NightGreets As GreetingDelegate
NightGreets = New GreetingDelegate(AddressOf Goodnight)

So, the entire thing can be summed up as:

AllGreets = [Delegate].Combine(AllGreets, _
   New GreetingDelegate(AddressOf Goodnight))

As like a function, to add a function reference to a delegate's invocation list, a delegate class provides a function to remove a function reference from the delegate invocation list.

For example:

Console.WriteLine("Removing 'GoodEvening' Reference...")
AllGreets = [Delegate].Remove(AllGreets, EveningGreets)

An Invoke function call on this multicast delegate will call all the functions whose references are stored in the invocation list of that delegate object.

Finally, while concluding multicast delegates, I can say that, it differs from a regular delegate in that it may contain references to more than just one method. Methods in a multicast delegate are executed synchronously when the multicast delegate is invoked, and in the order in which they are added to the list. If one of the called method raises an exception, then the delegate ceases, and the exception is propagated to the delegate caller.

All of the above code used in this article have been put in the samples. You can download and run it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here