Recipe 15.4 Polling an Asynchronous Delegate
Problem
While
an asynchronous delegate is executing, you need to continuously poll
it to see whether it has completed. This ability is useful when you
need to monitor the length of time it takes the asynchronous delegate
to execute or if you need to monitor other objects in the system in
parallel with this asynchronous delegate, possibly to determine which
object finishes first, second, third, and so on. It can also be
useful when performing a continuous task, such as displaying an
indicator to the user that the asynchronous operation is still
running.
Solution
Use the IsCompleted
property of the IAsyncResult interface to
determine when the asynchronous call has completed. The following
example shows how this is
accomplished:
using System;
using System.Threading;
public class AsyncAction
{
public void PollAsyncDelegate( )
{
// Set up the delegate
AsyncInvoke method1 = new AsyncInvoke(TestAsyncInvoke.Method1);
// Define the AsyncCallback delegate.
AsyncCallback callBack = new AsyncCallback(TestAsyncInvoke.CallBack);
IAsyncResult asyncResult = method1.BeginInvoke(callBack,method1);
while (!asyncResult.IsCompleted)
{
// give up the CPU for 1 second
Thread.Sleep(1000);
Console.Write('.');
}
Console.WriteLine("Finished Polling");
try
{
int retVal = method1.EndInvoke(asyncResult);
Console.WriteLine("retVal: " + retVal);
}
catch (Exception e)
{
Console.WriteLine(e.ToString( ));
}
}
}
The following code defines the AsyncInvoke
delegate and the asynchronously invoked static method
TestAsyncInvoke.Method1:
public delegate int AsyncInvoke( );
public class TestAsyncInvoke
{
public static int Method1( )
{
Console.WriteLine("Invoked Method1");
return (1);
}
public static void CallBack(IAsyncResult ar)
{
// Retrieve the delegate.
AsyncInvoke ai = (AsyncInvoke) ar.AsyncState;
// Call EndInvoke to retrieve the results.
int retVal = ai.EndInvoke(ar);
Console.WriteLine("retVal: " + retVal);
}
}
Discussion
The delegate, AsyncInvoke, is invoked
asynchronously using its BeginInvoke method. The
BeginInvoke method
returns an IAsyncResult object, which allows
access to the result information from an asynchronous operation.
If the delegate were to accept a string and an
int, in this order, the
BeginInvoke method would be defined as this:
public IAsyncResult BeginInvoke(string s, int i, AsyncCallback callback,
object state)
For this recipe the callback and
state parameters are set to
null. The callback
parameter could call back at completion into the code that invoked
it, but for this example, it is a no-op.
To poll for the completion of the method1
delegate, we get the IsCompleted property
of the IAsyncResult object that is returned by the
BeginInvoke method. The
IsCompleted property returns
true if the method1 delegate
has completed its operation or false if it has
not. This property can be called continuously within a loop to check
whether the delegate has finished.
Once the method1 delegate has finished its
asynchronous processing, the results of the operation can be
retrieved through a call to the EndInvoke method.
The compiler also creates this method dynamically, so that the return
value of the delegate can be accessed through the
EndInvoke method—as well as any
out or ref parameters that the
delegate accepts as parameters.
The
EndInvoke method returns an object of the same
type as the return value of the asynchronous delegate. An
EndInvoke method called on a delegate of the
following signature:
public delegate long Foo(ref int i, out string s, bool b);
will be defined as follows:
public long EndInvoke(ref int i, out string s, IAsyncResult result)
Notice that the return type is a long and only the
ref and out parameters of the
original delegate are in the signature for this method. The
EndInvoke method contains only the output
parameters of the delegate or those marked as ref
or out.
|
If the
asynchronous delegate throws an exception, the only way to obtain
that exception object is through the EndInvoke
method. The EndInvoke method should be wrapped in
an exception handler.
|
|
Once the while loop of the
PollAsyncDelegate method in this recipe is
exited—meaning that the asynchronous delegate has
completed—the EndInvoke method can be safely
called to retrieve the return value of the delegate as well as any
ref or out parameter values. If
you want to obtain these values, you must call the
EndInvoke method; however, if you do not need any
of these values, you may leave out the call to the
EndInvoke method.
See Also
See the "IAsyncResult Interface,"
"AsyncResult Class,"
"BeginInvoke Method," and
"EndInvoke Method" topics in the
MSDN documentation.
|