FREE BOOK

Chapter 5: Event-Based Programming

Posted by Apress Free Book | ASP.NET January 02, 2009
In this chapter, we explore the intricacies of working with server control events.

Delegates

Delegates are similar to interfaces-they specify a contract between the publisher and the subscriber. Although an interface is generally used to specify a set of member functions, a delegate specifies the signature of a single function. To create an instance of a delegate, you must create a function that matches the delegate signature in terms of parameters and data types.

Delegates are often described as safe function pointers; however, unlike function pointers, delegates call more than one function at a time and can represent both static and instance methods. Also unlike function pointers, delegates provide a type-safe callback implementation and can be secured through code access permissions as part of the .NET Framework security model.

Delegates have two parts in the relationship: the delegate declaration and the delegate instance or static method. The delegate declaration defines the function signature as a reference type. Here is how a delegate is declared:

public delegate int PrintStatusNotify (object printer, object document) ;

Delegates can be declared either outside a class definition or as part of a class through the use of the delegate keyword. The .NET Framework Delegate class and the .NET Framework MulticastDelegate class serve as the base classes for delegates, but neither of these classes is creatable by developers; instead, developers use the delegate keyword. As background, the MulticastDelegate base class maintains a linked list of delegates that are invoked in order of declaration when the delegate is fired, as you will see in our example in the next section.

One question that arises with delegates is what happens if an invoked method throws an exception. Does the delegate continue processing the methods in the invocation list ? Actually, if an exception is thrown, the delegate stops processing methods in the invocation list. It does not matter whether or not an exception handler is present. This makes sense because odds are that if an invoked method throws an exception, methods that follow may throw an exception as well, but it is something to keep in mind.

Working with Delegates

In this section we create a console-based application to demonstrate how delegates work. In our example, we declare a very simple delegate that takes one parameter:

delegate void SimpleMulticastDelegate(int i);

We next declare a class that contains two class instance methods and one static method. These methods match the signature of the previous delegate declaration:

public class DelegateImplementorClass
{
public void ClassMethod(int i)
{
Console.WriteLine("You passed in " + i.ToString() +" to the class method");
}
static public void StaticClassMethod(int j)
{
Console.WriteLine("You passed in "+ j.ToString() +" to the static class method");
}
public void YetAnotherClassMethod(int k)
{
Console.WriteLine("You passed in " + k.ToString() +" to yet another class method");
}
}


In method Main, the entry point of any console application in .NET, we put the delegate to work. Here we declare an instance of DelegateImplementorClass, as we will add instance methods from this class as subscribers to our delegate:

DelegateImplementorClass ImpClass = new DelegateImplementorClass();

We next declare an instance of our delegate, adding an instance method to the delegate
invocation list that will be called when the delegate instance executes:

SimpleMulticastDelegate d = new SimpleMulticastDelegate(ImpClass.ClassMethod);

Firing the delegate is simply a matter of calling the delegate instance function:

d(5);

The rest of method Main adds additional methods to the delegate's invocation list. Listing 5-1 is the full code listing. Figure 5-3 shows the output. Notice how each subsequent call to the delegate reflects this in the output. Each time the delegate fires, it passes the parameter value to each subscriber in its invocation list, taking advantage of multicasting behavior.

Listing 5-1.Delegates in Action

using System;
namespace ControlsBookWeb.Ch05
{
delegate void SimpleMulticastDelegate(int i);
public class DelegateImplementorClass
{
public void ClassMethod(int i)
{
Console.WriteLine("You passed in " + i.ToString() +"
to the class method");
}
static public void StaticClassMethod(int j)
{
Console.WriteLine("You passed in "+ j.ToString() +"
to the static class method");
}
public void YetAnotherClassMethod(int k)
{
Console.WriteLine("You passed in " + k.ToString() +"
to yet another class method");
}
}
class main
{
[STAThread]
static void Main(string[] args)
{
DelegateImplementorClass ImpClass = new DelegateImplementorClass();
SimpleMulticastDelegate d =
new SimpleMulticastDelegate(ImpClass.ClassMethod);
d(5);
Console.WriteLine("");
d +=
new SimpleMulticastDelegate(DelegateImplementorClass.StaticClassMethod);
d(10);
Console.WriteLine("");
d += new SimpleMulticastDelegate(ImpClass.YetAnotherClassMethod);
d(15);
}
}
}



Figure 5-3. Output from our work with delegates

Stepping back for a minute, you can see how delegates quite successfully fulfill the requirements of the publisher/subscriber model. Here we have the member function Main using an instance of the delegate to send messages to subscribing methods in the DelegateImplementorClass class. As long as the subscribing methods match the delegate signature, the delegate is happy to add those methods to its invocation list, and it promptly processes this list each time it is invoked with a call to d().

If you step through this code with the debugger, you will notice that methods on the delegate's invocation list are synchronously called in the order that they are added to the invocation list. The syntax for adding a delegate to the invocation list may seem strange at first, because what we are really adding is something more akin to function pointers than, say, an integer. The magic behind this is the keyword delegate and the .NET infrastructure provided by the System.Delegate and System.Delegate.MulticastDelegate classes. The result is that the language compiler simplifies things by providing a keyword that developers use to plug into the delegate infrastructure.

Total Pages : 12 12345

comments