Working with Delegates

Delegates let you pass methods as parameters. They provide you with another form of polymorphism, because you can assign methods to delegates at runtime, leaving the rest of your code unchanged but calling the methods you specify at runtime. You declare a delegate like this:

 
 [  attributes  ] [  modifiers  ] delegate  result-type identifier  ([  formal-parameters  ]); 

Here are the parts of this statement:

  • attributes (Optional) Hold additional declarative information, as we'll see in Chapter 14.

  • modifiers (Optional) The allowed modifiers are new and a valid combination of the four access modifiers.

  • result-type The result type, which matches the return type of the method.

  • identifier The delegate name .

  • formal-parameters (Optional) The parameter list. If a parameter is a pointer, the delegate must be declared with the unsafe modifier.

Here's an example. Say that you had a method, Caller , to which you wanted to pass other methods in order to call those methods. For example, if you had a method named Display that you wanted to have Caller call, you could pass a delegate to Caller , and Caller could use that delegate to call Display .

FOR C++ PROGRAMMERS

In C++, the counterpart to delegates is the function pointer, but delegates are objects, and are safe in ways that pointers can't be. Delegates don't exist in C++, making all the material from this point to the end of the chapter related to C# only.


Here's how it works in code; you start by declaring a new delegate like this:

 
 delegate void CallerDelegate(string text); 

Now you can set up Caller to accept a delegate of the type we've just created:

 
 delegate void CallerDelegate(string text);  public static void Caller(CallerDelegate SomeMethod)  {   .   .   . } 

Inside Caller , we can use the delegate as we would any method, so to call Display with the text "No worries." , we use this code:

 
 public static void Caller(CallerDelegate SomeMethod) {  SomeMethod("No worries.");  } 

All that's left is to create the Display method and pass it as a delegate to Caller . This method must have the same signature as the delegate declaration itself, which means the Display method that displays the text you pass to it, looks like this:

 
 public static void Display(string text) {   System.Console.WriteLine(text); } 

Now we just have to pass the Display method to Caller using a delegate. You can see how that works in ch04_13.cs, Listing 4.13.

Listing 4.13 Using a Delegate (ch04_13.cs)
 delegate void CallerDelegate(string text); class ch04_13 {  public static void Main()   {   Caller(new CallerDelegate(Display));   }  public static void Caller(CallerDelegate SomeMethod)   {    SomeMethod("No worries.");   }   public static void Display(string text)   {    System.Console.WriteLine(text);   } } 

Here's what you see when you run ch04_13.cs. Note that this example passes the Display method to Caller using a delegate, and that Caller calls Display using that delegate:

 
 C:\>ch04_13 No worries. 

In ch04_13.cs, we used a delegate with the static method Display , but delegates aren't restricted to static methods, of course. Say you have a class with a static member, DisplayStatic , and an instance method, DisplayInstance , both of which display a message:

 
 public class Messager {   public void DisplayInstance()   {    System.Console.WriteLine("Hello from the instance method!");   }   static public void DisplayStatic()   {    System.Console.WriteLine("Hello from the static method!");   } } 

You can use delegates to call both methods. When you pass the instance method to the delegate constructor, you just qualify the name of the method with the name of the object you want to use. You can see this in ch04_14.cs, Listing 4.14, where we pass obj.DisplayInstance to the delegate constructor.

Listing 4.14 Using a Delegate with Static and Non-Static Methods (ch04_14.cs)
 delegate void Delegate(); public class ch04_14 {   static public void Main()   {  Messager obj = new Messager();   Delegate delegate1 = new Delegate(obj.DisplayInstance);   delegate1();   delegate1 = new Delegate(Messager.DisplayStatic);   delegate1();  } } public class Messager {   public void DisplayInstance()   {    System.Console.WriteLine("Hello from the instance method!");   }   static public void DisplayStatic()   {    System.Console.WriteLine("Hello from the static method!");   } } 

Here's what you see when you run ch04_14.cs:

 
 C:\>ch04_14 Hello from the instance method! Hello from the static method! 

Delegate-Based Polymorphism

Delegates give you a new form of polymorphism, because you can assign a delegate variable different delegates at runtime. Your code stays the same, but different methods are called depending on which delegates you assign to the delegate variable. You can see an example of this in ch04_15.cs, Listing 4.15, where a single delegate variable, delegateVariable , is assigned two delegates and is used to call the corresponding methods at runtime.

Listing 4.15 Delegate-Based Polymorphism (ch04_15.cs)
 public class ch04_15 {   static public void Main()   {    Delegate delegateVariable;    Messager obj = new Messager();  delegateVariable = new Delegate(obj.Display1);   delegateVariable();   delegateVariable = new Delegate(obj.Display2);   delegateVariable();  } } public class Messager {  public void Display1()   {   System.Console.WriteLine("No worries.");   }   public void Display2()   {   System.Console.WriteLine("No worries again.");   }  } 

Here's what you see when you run ch04_15.cs. As you can see, we've used the same delegate variable to call two methods at runtime:

 
 C:\>ch04_16 No worries. No worries again. 

Creating Static Delegates

So far, the delegates we've created were created in the calling code. You can also create static delegates that are built into a class, so the calling code doesn't need to create its own delegate from scratch. For example, say that you had a class named Messager that has a Display method, and that you wanted to add a static delegate to Messager that corresponded to Display . To do that, you first declare a delegate type:

 
 public class Messager {  public delegate void delegate1();  static public void Display()   {    System.Console.WriteLine("No worries.");   } } 

Then you create a static delegate for Display , which we'll name DisplayAlias , like this:

 
 public class Messager {   public delegate void delegate1();  public static readonly delegate1 DisplayAlias = new delegate1(Display);  static public void Display()   {    System.Console.WriteLine("No worries.");   } } 

Now DisplayAlias is a static member of the Messager class, and a delegate for the Display method. The calling code no longer has to go to the trouble of creating its own delegate; it can simply use the Messager class's built-in DisplayAlias static delegate, as you see in ch04_16.cs, Listing 4.16.

Listing 4.16 Creating a Static Delegate (ch04_16.cs)
 public class ch04_15 {   static public void Main()   {  Messager.DisplayAlias();  } } public class Messager {   public delegate void delegate1();   public static readonly delegate1 DisplayAlias = new delegate1(Display);   static public void Display()   {    System.Console.WriteLine("No worries.");   } } 

Here's what you see when you run ch04_16.cs, showing that DisplayAlias is indeed a delegate for the Display method:

 
 C:\>ch04_16 No worries. 

Delegate Multicasting

You can also use a single delegate to call multiple methods, a process called multicasting . In fact, operators like + , - , += , and -= are overridden so you can add and remove delegates to other delegates. Let's take a look at an example. You want to send a message to three devicesthe display, the debug log, and the system log. We'll use these three methods, DisplayMethod , DebuggerMethod , and SystemLogMethod , to do so:

 
 public static void DisplayMethod(string text) {   System.Console.WriteLine("Sending to display: {0}", text); } public static void DebuggerMethod(string text) {   System.Console.WriteLine("Sending to debug log: {0}", text); } public static void SystemLogMethod(string text) {   System.Console.WriteLine("Sending to system log: {0}", text); } 

We can create a delegate for each one of these methods, Display , Debugger , and SystemLog , as well as a delegate for multicasting multiCaster :

 
 delegate void DisplayDelegate(string text); DisplayDelegate Display, Debugger, SystemLog, multiCaster; Display = new DisplayDelegate(DisplayMethod); Debugger = new DisplayDelegate(DebuggerMethod); SystemLog = new DisplayDelegate(SystemLogMethod); 

Now we can use + , - , += , and -= operators to combine delegates as we want in the multiCaster delegate. For example, to send the text "No worries." to the display and the debugger log at the same time, you can do this:

 
 multiCaster = Display + Debugger; System.Console.WriteLine("multiCaster = Display + Debugger"); multiCaster("No worries."); 

Here's what you see in this case. Note that both DisplayMethod and DebuggerMethod were called by using a single delegate:

 
 multiCaster = Display + Debugger Sending to display: No worries. Sending to debug log: No worries. 

We'll put multiCaster to work in ch04_17.cs, Listing 4.17, adding and removing delegates from this multicast delegate.

Listing 4.17 Multicasting Delegates (ch04_17.cs)
 delegate void DisplayDelegate(string text); public class ch04_17 {   public static void Main()   {  DisplayDelegate Display, Debugger, SystemLog, multiCaster;   Display = new DisplayDelegate(DisplayMethod);   Debugger = new DisplayDelegate(DebuggerMethod);   SystemLog = new DisplayDelegate(SystemLogMethod);   multiCaster = Display + Debugger;   System.Console.WriteLine("multiCaster = Display + Debugger");   multiCaster("No worries.");   System.Console.WriteLine();   multiCaster += SystemLog;   System.Console.WriteLine("multiCaster += SystemLog");   multiCaster("No worries.");   System.Console.WriteLine();   multiCaster -= Display;   System.Console.WriteLine("multiCaster -= Display");   multiCaster("No worries.");  }   public static void DisplayMethod(string text)   {     System.Console.WriteLine("Sending to display: {0}", text);   }   public static void DebuggerMethod(string text)   {     System.Console.WriteLine("Sending to debug log: {0}", text);   }   public static void SystemLogMethod(string text)   {     System.Console.WriteLine("Sending to system log: {0}", text);   } } 

Here are the results of ch04_17.cs, where you can see the + , += , and -= operators at work, adding and removing delegates as detailed in the text this example displays:

 
 C:\c#\ch04>ch04_17  multiCaster = Display + Debugger  Sending to display: No worries. Sending to debug log: No worries.  multiCaster += SystemLog  Sending to display: No worries. Sending to debug log: No worries. Sending to system log: No worries.  multiCaster -= Display  Sending to debug log: No worries. Sending to system log: No worries. 


Microsoft Visual C#. NET 2003 Kick Start
Microsoft Visual C#.NET 2003 Kick Start
ISBN: 0672325470
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net