Introduction to Delegates
Written by Mike James   
Wednesday, 19 May 2010
Article Index
Introduction to Delegates
Signatures and Methods

Delegates are C#'s original way of allowing you to work with functions as if they were first class objects. The aim may be simple but the need to define a type and then an instance of the type can be confusing. Let's see if we can make it all seem logical.

There is a newer version of this article. See: Deep C# - Delegates.

 

Banner

 

Delegates are at the core of a number of different .NET facilities, events in particular.

It’s long been a truism that the way to get work done is to delegate, but what are C# delegates all about?

They seem to be just a complicated way of calling a method that you could just as easily call in the usual way. Of course the key is that a delegate really does delegate – it allows others to call a method on your behalf.

Let’s look at how it works and some of the more interesting ways that you can put it to work.

Delegates and their relationship to events is covered in another article.

Delegate basics

What is initially confusing is that to create a delegate you first have to create a type and then create an instance of the type. That is, delegate is a user-defined reference type that encapsulates a method.

Consider, for example, how to encapsulate the method:

public int hello(int param1)
{
MessageBox.Show(
"Hello delegate World"
+param1.ToString());
return(++param1);
}

 

First we need to define a delegate type that matches its signature – including, in this case, the return type:

delegate int HelloType(int param);

This delegate type defines the methods that it can encapsulate.

Next we have to create an instance of the type and supply it with the hello method to encapsulate:

HelloType HelloInst= new 
HelloType(hello);

If you prefer you can use the overloaded assignment operator:

HelloType HelloInst = hello;

to create an instance.

Now we can run the original Hello method by calling it directly in the usual way:

int i = hello(2);

or by using the delegate’s invoke method:

int i=HelloInst.Invoke(2);

or by calling the delegate instance as if it was the hello method:

int i=HelloInst(2);

This last form is just a convenience as it implicitly uses the Invoke method.

Invoke uses the same current thread to run the delegate and in this case you need to be aware of any potential “cross threading” problems that might arise.

This also means that the invocation is asynchronous and the calling code will wait until the delegate returns. You can invoke the delegate asynchronously using a thread from the thread pool using BeginInvoke or you could create a thread manually to run the delegate.

Delegate patterns

Why would you use a delegate rather than just calling a method?

The answer is simply that a delegate can be passed as a parameter to another method, so determining what method is called at run time.

In functional programming terms it converts a method or a function into a "first class object" i.e. one that can be used like any other object.

There are two well-known patterns that demand the use of a delegate.

The first is the “callback” or notification method which is supplied to an object for it to call with intermediate or final results of its working. Of course in this instance the object is usually run on a separate thread and the callback/notification method provides some asynchronous communication between the caller and the called thread.

The second well-known pattern is event handling. A delegate can be set up within and object so that clients can provide a method to be called when an event occurs.

If you think carefully you will see that there is little difference between the callback and the event pattern.

In both cases a delegate is called when some condition occurs – a buffer is full, the user has clicked a button, an error condition has been detected etc. However while events are based on delegates they add some additional structure – an add and remove accessor similar to a property.

A third, slightly less common, use is in creating a new thread of execution.

Banner

<ASIN:1449380344>

<ASIN:1430225378>
<ASIN:0470447613>

<ASIN:1933988924>

<ASIN:3540921443>



Last Updated ( Thursday, 07 January 2016 )