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.
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); } }
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(strings
, inti
, AsyncCallbackcallback
, objectstate
)
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 inti
, out strings
, boolb
);
will be defined as follows:
public long EndInvoke(ref inti
, out strings
, IAsyncResultresult
)
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.