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.
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); } }
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.