DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 7.4 Converting a Synchronous Delegate to an Asynchronous Delegate

Problem

You have determined that one or more delegates invoked synchronously within your application are taking a long time to execute. This delay is making the user interface less responsive to the user. These delegates should be converted to asynchronous delegates.

Solution

A typical synchronous delegate is created in the following manner:

using System;

// The delegate declaration
public delegate void SyncInvoke( );

// The class and method that is invoked through the SyncInvoke delegate
public class TestSyncInvoke
{
    public static void Method1( )
    {
        Console.WriteLine("Invoked Method1");
    }
}

The code to use this delegate is:

public class DelegateUtilities
{
    public void TestSimpleSyncDelegate( )
    {
        SyncInvoke SI = new SyncInvoke(TestSyncInvoke.Method1);
        SI( );
    }
}

This delegate can be called asynchronously on a thread obtained from the thread pool by modifying the code as follows:

public class DelegateUtilities
{
    public void TestSimpleAsyncDelegate( )
    {
        AsyncCallback CB = new AsyncCallback(DelegateCallback);

        SyncInvoke ASI = new SyncInvoke(TestSyncInvoke.Method1);
        IAsyncResult AR = ASI.BeginInvoke(CB, null);
    }

    // The callback that gets called when Method1 is finished processing
    private static void DelegateCallback(IAsyncResult iresult)
    {
        AsyncResult result = (AsyncResult)iresult;
        AsyncInvoke ASI = (AsyncInvoke)result.AsyncDelegate;

        int retVal = ASI.EndInvoke(result);
        Console.WriteLine("retVal (Callback): " + retVal);
    }
}

Of course you might want to also change the TestSyncInvoke class name to TestAsyncInvoke and the SyncInvoke delegate name to AsyncInvoke just to be consistent with your naming.

The previous example shows how to call a delegate that accepts no parameters and returns void. The next example shows a synchronous delegate that accepts parameters and returns an integer:

using System;

// The delegate declaration
public delegate int SyncInvoke(string message);

// The class and method that is invoked through the SyncInvoke delegate
public class TestSyncInvoke
{
    public static int Method1(string message)
    {
        Console.WriteLine("Invoked Method1 with message: " + message);
        return (1);
    }
}

The code to use this delegate is:

public class DelegateUtilities
{
    public void TestComplexSyncDelegate( )
    {
        SyncInvoke SI = new SyncInvoke(TestSyncInvoke.Method1);
        int retVal = SI("Synchronous call");
        Console.WriteLine("Sync: " + retVal);
    }
}

This synchronous delegate can be converted to an asynchronous delegate in the following manner:

using System;
using System.Runtime.Remoting.Messaging;

public class DelegateUtilities
{
    public void TestCallbackAsyncDelegate( )
    {
        AsyncCallback CB = new AsyncCallback(DelegateCallback);

        SyncInvoke SI = new SyncInvoke(TestSyncInvoke.Method1);
        IAsyncResult AR = SI.BeginInvoke("Asynchronous call message", CB, null);

        Console.WriteLine("WORKING...");
    }

    // The callback that gets called when Method1 is finished processing
    private static void DelegateCallback(IAsyncResult iresult)
    {
        AsyncResult result = (AsyncResult)iresult;
        AsyncInvoke ASI = (AsyncInvoke)result.AsyncDelegate;

        int retVal = ASI.EndInvoke(result);
        Console.WriteLine("retVal (Callback): " + retVal);
    }
}

Discussion

Converting a delegate from being invoked synchronously to asynchronously is not an overly complicated procedure. You need to add calls to both BeginInvoke and EndInvoke on the delegate that is being called synchronously. A callback method, DelegateCallback, is added, which gets called when the delegate is finished. This callback method then calls the EndInvoke method on the delegate invoked using BeginInvoke.

The notification callback method specified in the callback parameter accepts a single parameter of type IAsyncResult. This parameter can be cast to an AsyncResult type and used to set up the call to the EndInvoke method. If you want to handle any exceptions thrown by the asynchronous delegate in the notification callback, wrap the EndInvoke method in a try/catch exception handler.

See Also

See the "Delegate Class" and "Asynchronous Delegates" topics in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section