Tuesday, 21 July 2009

Delegates Explained in Plain English

Delegates are fundamental to the .NET Framework (events and callbacks wouldn't work without them) and can be extremely powerful to the .NET Developer once they come to grasps with exactly what they are and how to use them. In this blog I will consider aspects of a real world situation in which delegates are useful, after which I will explain, in illustrative terms exactly what delegates are all about. You will see how delegates are an intrinsic part of the events structure in the .NET framework, but also why they are useful in their own right. First, though, we need to understand a little about the origins of delgates in the .NET framework.

The origins of delegates

Delegates in .NET languages such as C# and VB.NET are akin to function pointers in C++. I have found that simply being aware of this pseudonym is extremely helpful in understanding delegates. The term helps us to understand that delegates allow a developer to provide a pointer to a method/function/sub etc. But when would a developer find this to be useful?

Where delegates are needed

Let's say, for example, that you are developing a Windows Forms application and you want to open a new instance of a form. You want your new form to do some work and update its opener at some point down the line.

To expand, let's take a real world example. I developed a Windows Forms application in C# that was used for managing staff and contracts within a cleaning business. This was an MDI application and had toolbars on the MDI parent form with lists of staff and contracts so that the user could easily select a member of staff or a contract to work on. When the user selected a member of staff or contract a new form was opened. There was also, as you would expect, forms for creating new staff members and new contracts. These forms needed to update the main form whenever a new member of staff or a new contract was added to the system so that the main form could refresh its lists. In a basic application you might accomplish this by opening these forms modally directly from the main form and then updating the lists when the new staff form closes. Something along the lines of:

//... MainForm code ...
NewStaffForm _nuForm = new NewStaffForm();

//Assume that the user clicked the OK button on the
//NewStaffForm and added a new member of staff

However, this is extremely limiting. The ShowDialog() method for opening the NewStaffForm form holds execution of the subsequent code within the MainForm until the NewStaffForm has closed.

What if you want your application to be more flexible than that and keep your MainForm useable while the NewStaffForm is in use? What if you want your NewStaffForm to do more than just notify your MainForm that it's created a new user? Say, for example, you want it to pass information back to the MainForm? This is where delegates come in.

In particular, in this instance, an event would be useful; but as you will see, in .NET delegates are inseparable from events.

Revising our code to use delegates and events

No doubt you're very familiar with events and have made extensive use of events belonging to other objects. However, until you actually create your own events you probably don't really know or care what's going on. So, let's revise our code and explain what we're doing at each stage.

First, we want to declare an event handler in our code. It doesn't really matter where this event handler is declared so long as it has public scope so that it can be seen by other objects. A delegate can be declared outside of a class declaration, as it is essentially a type declaration, just as a class is.

public delegate void NewStaffCreatedHandler(StaffMember NewStaffMember)

Notice that this event handler is actually a delegate. Also, notice that it takes a parameter of type StaffMember. This is a custom type specific to this program. It's details are not relevant to this blog, so I'll go no further in describing it.

Next, we declare an event in our NewStaffForm.

public event NewStaffCreatedHandler NewStaffCreated;

Notice that the event has, as its type, the event handler we just declared.

Next, we write code to raise the event. This looks very much like a method call:

protected void CreateNewStaffMember()
StaffMember _newStaffMember = new StaffMember();
//... Code to create the new StaffMember...
//Raise the event
Where exactly is the code that runs when the event is raised? Remember what we said earlier about the origins of delegates lying in C++ function pointers. As I said, remembering this pseudonym helps to understand what delegates are all about.

When the event is raised we are actually calling the function(s) (or method(s)) that the delegate points to. How do we point the delegate to a method? Well, where events are concerned I'm willing to bet that it's something you already know how to do. We simply assign a method to the event be doing the following in our MainForm form.

//Create an instance of the NewStaffForm and assign a method to the NewStaffCreatedHandler
NewStaffForm _nuForm = new NewStaffForm();
_nuForm.NewStaffCreated += new NewStaffCreatedHandler(NewStaffForm_NewStaffCreated);

//This is the method that the delegate points to
void NewStaffForm_NewStaffCreated(StaffMember NewStaffMember)
NewStaffMember.AddedToList = true; //Do something with the StaffMember object that was passed with the delegate

Explaining what's happening in Plain English

Why are delegates called delegates?

In the real world a delegate is usually a person. What function do they serve? Well, imagine a large company wants to have a presence at a conference. The whole company can't relocate to the conference venue for its duration - that would be impractical. Rather, the company assigns a delegate (or delegates) to go and represent the company at the conference. The delegate might be given specific instructions about how he or she is to behave when there, which hotel they are to stay in, what their budget for food & drink is etc, but the delegate, being a human being, has relative freedom besides these constraints. When the delegate returns from the conference he or she may have to report back to the company about it.

In the .NET framework a delegate fulfils a similar purpose. Where one class may wants to be represented within another class it can use a delegate. This is a lot more efficient that passing itself to the other class in its entirety, and is a lot more flexible. The delegate has to conform to certain limitations, though, just as the real world delegate does.

When a delegate is declared it is declared much along the lines of a method/sub/function declaration. For example, in C#, a delegate declaration might look like:

public delegate void NewStaffCreatedHandler(StaffMember NewStaffMember)

It is given a scope public, a return type void (although it could equally be any other type), and specifies parameters. This constitutes the agreement as to how the implementation of the delegate (i.e. the method/sub/function it points to) must behave. In other words, any method/sub/function that this delegate points to must return a void and take a StaffMember object parameter.

The most common event handler delegate EventHandler, for example, has the following declaration:

public delegate void EventHandler(object sender, EventArgs e);

All events are of a delegate type. In other words, all events are declared with a specific delegate as their representative. For example, a delegate at a Microsoft conference could report back on an event that a delegate at an Sun conference couldn't (although they in turn could report back on an event that the Microsoft delegate couldn't), because they weren't in attendance at the same conference.

So, if you wanted to declare an event in your program that used the standard EventHandler delegate you would declare it as follows:

public event EventHandler MyEvent;

Delegates aren't restricted to events

Although we've used events as a springboard for our explanation of delegates, there's no reason to limit delegates to this useage. In the MDI application I mentioned above I didn't actually use events at all (although, as can be seen, I could easily have). I knew that I wanted my child forms to update my parent forms by means of a function call. This created the environment for the use of a delegate, but to save on the the extra declaration of an event in my child form I simply declared a constructor for my child forms that took my delegate as a parameter. For example:

public delegate void NewStaffCreatedDelegate(StaffMember
public class NewStaffForm : Form{
public NewStaffForm (NewStaffCreatedDelegate callbackDelegate){
//Constructor logic

Then, when I wanted to callback to my parent form I simply invoked the delegate:


Passing a delegate to the constructor of the child form is very easy. Simply pass the name of the method that you want the delegate to point to. For example:

NewStaffForm myChildForm = new NewStaffForm(myCallBackMethod);
Don't forget, though, that the method being passed MUST agree to the rules set out for the delegate. So, it's signature must be the same as that of the delegate.

void myCallBackMethod(StaffMember newStaffMember){
//Implementation logic


In essence, delegates allow one class to invoke code in another class, without necessarily needing to care where that code is, or even if it exists at all...

Let's go back to the conference scenario to explain. Microsoft may host a conference and send out invitations to many different partner companies. At the conference one of their lead developers may provide a sneak preview of a new product. Delegates in attendance may be given a beta copy to take back with them for trial. Microsoft doesn't care whether or not all of the companies they invited chose to send a delegate or not. Their conference won't halt just because one company declined to be represented.

Likewise, one class may expose a property, method parameter or event that allows another class to send a delegate to its code. The delegate (or more to the point the implementation of the delegate, the method/sub/function that the delegate points to) will have to conform to the delegate's signature. Most classes that send a delegate may choose to provide an implementation (i.e. logic for the method/sub/function) but some may not. The inviting class doesn't really care... it will still do what it does and make use of the delegate. For example, all TextBox control's expose a KeyPress event, but not every form that uses a TextBox control will choose to provide an implementation for the KeyPress handler. The TextBox control will still work, it's just that nothing will happen when a user presses a key within it - because no implementation of the delegate has been provided by the form.

In conclusion, as you will see from the above, once you understand what delegates are for, and what they enable, you will likely start to realise many different scenarios in which you can use them. I strongly believe that you can't really claim to be a .NET developer without understanding this fundamental part of the framework. If you've struggled to understand delegates in the past, or even if you've never really cared much about them before, I hope this blog will help to clarify matters and help you to become a better programmer.

No comments:

Post a Comment