Flylib.com

Books Software

 
 
 

5.4 Accessing Delegate Names Within a Multicast Delegate

 <  Day Day Up  >  

5.4 Accessing Delegate Names Within a Multicast Delegate

You want to view which methods are attached to a multicast delegate.


Technique

To retrieve an array of delegates that are attached to a multicast delegate, call the GetInvocationList method from the multicast delegate instance. You can access the method name and additional method information on each delegate by using the Method property defined in the delegate. This step returns a MethodInfo object, and you find the name of the method bound to that delegate by accessing the Name property of that object:


class StringPrinterDelegate

{

    public delegate void PrintString( string s );



    // delegate passed as parameter

    public static void PrintWithDelegate( PrintString psDelegate, string s )

    {

        Console.Write( "Invocation List Method Names: " );



        // enumerate through each delegate in invocation list

        foreach( Delegate dg in psDelegate.GetInvocationList() )

            Console.Write( dg.Method.Name + " " );



        Console.WriteLine();



        // call delegate

        psDelegate( s );

    }

}

Comments

Whenever you start programming anything that is dynamic in nature, you lose any predefined knowledge about objects or methods or anything else that you normally know before you compile. In other words, when you want to call a method, you know what the method name is and you can use that information to output tracing or debug information. However, once you enter the dynamic realm where objects are attached during runtime, or the invocation of methods occurs dynamically based on the running state of the application, you don't always know what object is being accessed or what method is being called at any given point in time. That is, you don't know unless you have some sort of runtime type information or reflection capabilities built into the language or your application.

The .NET Framework is a very dynamic environment and as such has rich support for runtime type information and the ability to inspect an object and its methods at any point. The multicast delegate class is no exception. There are a few reasons why you would want to inspect the methods that a multicast delegate is bound with, the most probable reason being debugging.

You saw earlier how to use the GetInvocationList to access individual delegates within a multicast delegate so you can remove them from the invocation list. One thing that wasn't pointed out was that you can also enumerate this list to gather information about each delegate. The invocation list is simply an array of delegate objects whose type is System.Delegate . Within that class is a Method property that contains any information you need about the method to which the delegate is bound. Although this recipe singles out the Name property to determine the name of the bound method, there are other properties that you might find useful.

 <  Day Day Up  >  
 <  Day Day Up  >  

5.5 Calling Delegates Asynchronously

A delegate can take a long time to return; you want to invoke the delegate asynchronously so that it returns immediately and notifies you when it has finished.


Technique

In addition to the delegate and the method to bind to that delegate, create a method that is used to process the results of the asynchronous method call. This method takes a single IAsyncResult parameter. This method is called when the delegate method has finished, and you can obtain results by calling the EndInvoke method obtained from the IAsyncResult object.


class TearCallback

{

    public void PrintTearResult( IAsyncResult ar)

    {

        TearWebPage tear = (TearWebPage)((AsyncResult)ar).AsyncDelegate;

        Console.WriteLine( "TearPage returned {0}", tear.EndInvoke( ar ) );

    }

}

Before invoking the delegate, create an AsyncCallback object by passing the method name of the result method mentioned earlier. If this method is not static, use an instance of the object that implements this method followed by the dot operator ( . ) and the method name.

Listing 5.2 Asynchronous Delegates
using System;

using System.Threading;

using System.Runtime.Remoting.Messaging;

using System.Net;

using System.IO;

using System.Text;



namespace _5_AsynchronousDelegate

{

     public delegate bool TearWebPage( string url );



    class Class1

    {

        [STAThread]

        static void Main(string[] args)

        {

            // create delegate attached to DoAsynchSleep method

            TearWebPage tear = new TearWebPage( new WebTear().TearPage );



            // create result class and create callback object

            TearCallback result = new TearCallback();

            AsyncCallback ascb = new AsyncCallback( result.PrintTearResult );



            // invoke the delegate asynchronously

            IAsyncResult ar = tear.BeginInvoke (

                "http://www.samspublishing.com", ascb, null );



            // long operation here

            Thread.Sleep(10000);

        }

    }



    // Insert TearCallback implementation here



    class WebTear

    {

        public bool TearPage( string url )

        {

            // final web page text variable

            StringBuilder pageText = new StringBuilder("");



            // create URI and a web request

            Uri HttpSite = new Uri(url);

            HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(HttpSite);

            wreq.AllowAutoRedirect = true;



            // get the stream associated with the web request

            Stream webStream = wreq.GetResponse().GetResponseStream();



            // create byte array for chunked data

            byte[] webResponse = new byte[1024];

            int bytesRead = 0;



            do

            {

                // read first 1024 bytes

                bytesRead = webStream.Read( webResponse, 0, 1024 );



                // append current chunk to final result

                if( bytesRead > 0 )

                {

                    pageText.Append( Encoding.ASCII.GetString

                        ( webResponse, 0, bytesRead ));

                }



                // continue until no more bytes are being read

            } while( bytesRead > 0 );



            // output final result

            Console.WriteLine( pageText.ToString() );

            return true;

        }

    }

}

To invoke the delegate asynchronously, call the BeginInvoke method defined in the delegate, passing the necessary delegate parameters followed by the AsyncCallback object and an optional object used to hold state information, as shown in Listing 5.2.

Comments

As fast as computers are nowadays, sometimes fast still isn't fast enough. Whether the lag occurs due to disk I/O, network traffic, or long computations , you can use this lag to your advantage by performing additional work until an operation finishes. Asynchronous method calls allow you to invoke a method and not wait for it to complete before you begin other tasks . As you work through the .NET Framework, you will see that you can perform asynchronous method calls in a variety of different ways. This recipe shows how to invoke a delegate asynchronously.

The initial code for the delegate is the same as the previous recipes in this chapter. The delegate is the same as well as its implementation and the code used to bind the two together. The difference is at the point where the actual work needs to happen, the point of delegate method invocation. The first recipe in this chapter mentioned that the delegate class generated upon using the delegate keyword contains three methods : Invoke , BeginInvoke , and EndInvoke . Up to this point, the Invoke method was called transparently anytime the delegate was used. Invoke performs a classic synchronous method call. In other words, Invoke does not return until the method has finished to completion. You use BeginInvoke and EndInvoke , however, when you want to call the delegate asynchronously.

The code listing for this recipe creates a class that contains a method implementation for the TearWebPage delegate. This method, TearPage , uses classes within the .NET Framework to open a connection with a remote Web server and request a page. If called synchronously, this method might not return for a while if network traffic is high, so we made the decision to call it asynchronously.

The first step, other than actually creating the delegate method implementation, of course, is to create a method used as the callback method. When the delegate method finishes, this method is called to notify the user of the delegate. The method itself accepts a single parameter whose data type is IAsyncResult . Before looking at the implementation of this method, you first have to understand how BeginInvoke works.

After you bind a method to a delegate, you have to set up the necessary objects used for the delegate callback. To do so, create an instance of the class that contains the callback method if this method isn't static. Next, create an AsyncCallback object passing the callback method name as the parameter. You can then call the BeginInvoke method. BeginInvoke is dynamically created based on the parameters. When you call BeginInvoke , as shown in the listing earlier, you provide each parameter necessary similar to the way you do if you were performing a synchronous method call. However, you need two additional parameters after the delegate parameter list. The first is the AsyncCallback method created earlier; the delegate class uses it when the method finishes. The final parameter can be any object that you want to create to hold state information. Because this parameter is optional and not used within the implementation of the BeginInvoke method itself, this parameter can be null . Once the BeginInvoke method is called, it returns immediately even though the method to which the delegate is bound has not finished. You can then perform additional processing as you wait for the delegate method to finish.

Once the delegate method finishes, your callback method created earlier is called. If you recall, this method receives a IAsyncResult parameter, which you can use to access the delegate instance that has finished. To do so, cast the IAsyncResult to an AsyncResult object and then cast the AsyncDelegate property of that object to your delegate class, as shown in the PrintTearResult method earlier. To access the return value, call the EndInvoke method defined in the delegate class. The EndInvoke is also dynamically created using the return value of the delegate method as its return value. Figure 5.4 shows the result of running Listing 5.2.

Figure 5.4. You download a Web page using an asynchronous delegate and access its result using the delegate callback method.

graphics/05fig04.jpg

 <  Day Day Up  >