5.1 Defining and Using Delegates

 <  Day Day Up  >  

You want to define a delegate and allow the use of that delegate within a member function.


Technique

A delegate is similar to a member method but does not contain a method body. Define a member method using the delegate keyword following the access modifier. Because there is no body associated with the delegate, place a semicolon instead of braces at the end of the method header. For member methods that will use an instance of that delegate, add a parameter whose data type is the name of the delegate method name followed by a parameter identifier:

 
 class StringPrinterDelegate {     public delegate void PrintString( string s );     // delegate passed as parameter     public static void PrintWithDelegate( PrintString psDelegate, string s )     {         psDelegate( s );     }     // internal delegate implementation     public static void InternalImp( string s )     {         Console.WriteLine( s );     } } 

To use a delegate within a client application, create an instance of the delegate method whose data type consists of the name of the class, the dot ( . ) operator, and the name of the delegate. The constructor expects the name of the function that implements this delegate as a parameter. You can locate this delegate implementation within the class that implements the delegate or within a different class, as shown in the code example via the InternalImp method, as long as the method header is identical. Listing 5.1 shows how to create a client application that instantiates two instances of the delegate shown earlier. Each delegate uses a different method implementation using either the static method in the same class as the delegate or the method within the client application class itself. Additionally, the listing also shows how to pass a delegate instance to a method. The output of Listing 5.1 appears in Figure 5.1.

Listing 5.1 Defining Delegates
 using System; namespace _1_Delegates {     class Class1     {         [STAThread]         static void Main(string[] args)         {             // instantiate delegates             StringPrinterDelegate.PrintString internalPrint =                 new StringPrinterDelegate.PrintString                     ( StringPrinterDelegate.InternalImp );             StringPrinterDelegate.PrintString firstCharPrint =                 new StringPrinterDelegate.PrintString( FirstCharPrint );             // get string from user             Console.Write( "Enter a string: " );             string input = Console.ReadLine();             // call delegates directly             internalPrint( input );             firstCharPrint( input );             // pass delegates as parameter             StringPrinterDelegate.PrintWithDelegate( internalPrint, input );             StringPrinterDelegate.PrintWithDelegate( firstCharPrint, input );         }         // external delegate implementation         static void FirstCharPrint( string s )         {             string[] splitStrings = s.Split( new char[]{' '} );             foreach( string splitString in splitStrings )             {                 Console.Write( "{0}", splitString[0] );                 for( int i = 0; i < splitString.Length; i++ )                     Console.Write( " " );             }             Console.WriteLine();         }     } } 
Figure 5.1. Delegates can be associated with different implementations, and you can define those implementations in different classes.

graphics/05fig01.gif

Comments

To delegate means to transfer the care or management of something to a different person or other object. A delegate within the .NET Framework acts like a method whose implementation is provided or delegated to some other object. In other words, an object declares that it supports a certain method but relies on different objects or methods to provide the actual implementation.

Looking at the syntax of a delegate, it's perfectly reasonable to assume that a delegate is a method because it resides in an object and it is declared much like other methods. However, a delegate is actually converted to a class when the source is compiled to (MSIL). This class name is the name you give to the delegate when you declare it, and the class itself is derived from System.MulticastDelegate , as shown in Figure 5.2, which shows the code listing earlier in the ILDasm tool. In the client application shown earlier, you can see that you use the new keyword on a delegate. Because a delegate is in actuality a class, the new keyword is creating an instance of that class.

Figure 5.2. A delegate is actually a class nested within its containing class.

graphics/05fig02.gif

Delegates have been compared to function pointers, and in some cases they are quite similar. The pointer in the delegate sense of the word is a managed pointer to the method, which provides the implementation for the delegate. Because this pointer is managed by the Common Language Runtime (CLR), it is secure, type safe, and verifiable , unlike its unmanaged counterpart . This pointer is passed into the constructor of the delegate when you use the new keyword. If you look at the intermediate language (IL) that is generated when an instance of a delegate is created, you see the instruction ldftn , which places a managed function pointer onto the runtime stack. So the question is now, how does the delegate class that is created call the method using the unmanaged pointer?

Looking at the delegate class in ILDasm, you can also see three methods within the class. The first two, BeginInvoke and EndInvoke , are used for asynchronous delegates, which are explained later in this chapter. The third method, Invoke , is where the implementation of the delegate is called. However, double-clicking on the method name in ILDasm shows the method signature with an empty body, as shown in Figure 5.3. When you see this sort of behavior, you will also usually see the attribute "runtime managed" on the method. When Invoke is called, the CLR retrieves the function pointer that was placed on the runtime stack (with the IL instruction ldftn mentioned earlier), and that is now a member variable within the delegate class, and uses it to call the actual method. The reason no IL shows up in the method is that the act of calling the actual delegate implementation happens within unmanaged code contained within the runtime.

Figure 5.3. A delegate's Invoke method is runtime managed.

graphics/05fig03.gif

To summarize the steps involved when the CLR creates a delegate, the first step is to convert the delegate into a class derived from System.MulticastDelegate during the compilation process. A client then creates an instance of that class passing a method, either static or nonstatic, to the constructor of that object. This step results in the IL instruction ldftn , which places a managed pointer to the method onto the stack. The delegate constructor places that managed pointer into a member variable within the delegate class. When the actual method is called, the runtime-managed Invoke method is called instead, and unmanaged code within the runtime finds the correct method, via the managed method pointer, and calls its implementation.

 <  Day Day Up  >  


Microsoft Visual C# .Net 2003
Microsoft Visual C *. NET 2003 development skills Daquan
ISBN: 7508427505
EAN: 2147483647
Year: 2003
Pages: 440

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