Retrieving Results from Asynchronous Delegates
When you execute a delegate asynchronously, control returns to the application immediately, before the delegate is done executing the function. Because the delegate hasn't completed, output parameters aren't yet known. Therefore you have to wait until the delegate is done executing to retrieve the output values. The delegate class provides a function called
EndInvoke
to retrieve output values. There are two ways of using
EndInvoke
depending on how you called
BeginInvoke
: writing code that waits, or providing a callback function.
To retrieve output parameters if you have code that waits for the delegates to finish:
-
If you invoked the delegates asynchronously and waited for the delegates to complete, you most likely have delegate
variables
such as del1 and del2, and
IAsyncResult
variables such as ar1 and ar2.
-
Type
object result = del1.EndInvoke(ar1, outparam1, outparam2);
where
result
is any variable to accept the result value. The type of result is shown as object, but it can be the specific type that the delegate function returns;
ar1
is the
name
of the variable holding the
IAsyncResult
value returned from the call to
BeginInvoke
;
outparam1
and
outparam2
are variables for each ref or out parameter specified in the delegate function (
Figure 10.20
).
Figure 10.20 Because the functions begin execution and return immediately, there's no way of knowing the return parameters on the BeginInvoke. You need to wait until they're done and then call EndInvoke to get the return values.
class Tasks
{
public bool Task1(string desc)
{
return true;
}
public static bool Task2(string desc)
{
return true;
}
}
delegate bool TaskDel(string desc);
public class WebForm1 :
System.Web.UI.Page
{
private void Page_Load(object sender,
System.EventArgs e)
{
Tasks tsks = new Tasks();
TaskDel del1 =
new TaskDel(tsks.Task1);
TaskDel del2 =
new TaskDel(Tasks.Task2);
IAsyncResult ar1 =
del1.BeginInvoke(
"Calling Task1...",null,null);
IAsyncResult ar2 =
del2.BeginInvoke(
"Calling Task2...",null,null);
System.Threading.WaitHandle[]
handles =
new System.Threading.WaitHandle[]
{ar1.AsyncWaitHandle ,
ar2.AsyncWaitHandle };
System.Threading.WaitHandle.
WaitAll(handles,2000,false);
bool retval1 = del1.EndInvoke(ar1);
bool retval2 = del2.EndInvoke(ar2);
}
}
To retrieve output parameters if you have a callback function:
The trick to remember when using a callback function is that you don't have the original delegate variable when the callback function executes. But you can retrieve it from the parameter of the callback function.
-
Type
DelegateTypeName del1 = (DelegateTypeName) ((System.Runtime.Remoting.Messaging.AsyncResult)ar). AsyncDelegate
; where
del
is any variable to hold the delegate object, and
ar
is the name of the input parameter.
-
Follow step 2 from the previous section to retrieve the output parameters with
EndInvoke
(
Figure 10.21
).
Figure 10.21 In the case of the system telling us when it's done executing the functions, we may not have the original delegate variables and we need them to call EndInvoke and retrieve the output parameters. Luckily, the system gives us the original delegate variable through the AsyncResult parameter.
class Tasks
{
public bool Task1(string desc)
{
return true;
}
public static bool Task2(string desc)
{
return true;
}
}
delegate bool TaskDel(string desc);
public class WebForm1 :
System.Web.UI.Page
{
public void FunctionDone (
IAsyncResult ar)
{
TaskDel del1 = (TaskDel)
((System.Runtime.Remoting.
Messaging.AsyncResult)ar).
AsyncDelegate;
bool result = del1.EndInvoke(ar);
}
private void Page_Load(object sender,
System.EventArgs e)
{
Tasks tsks = new Tasks();
TaskDel del1 =
new TaskDel(tsks.Task1);
TaskDel del2 =
new TaskDel(Tasks.Task2);
AsyncCallback cb = new
AsyncCallback(this.FunctionDone);
IAsyncResult ar1 =
del1.BeginInvoke(
"Calling Task1...",
cb
,null);
IAsyncResult ar2 =
del2.BeginInvoke(
"Calling Task2...",
cb
,null);
}
}
Tips
-
EndInvoke
can be used to retrieve the output parameter of the function, plus any ref or out parameters of the delegate function.
-
Every delegate object has a
BeginInvoke
function and an
EndInvoke
function as well as the Invoke function, which is used for synchronous operation. Other classes
mimic
this behavior: They provide a
BeginInvoke/EndInvoke
for asynchronous operations and an Invoke function for synchronous operations. For example, the class WebClient also uses the same pattern for asynchronous vs. synchronous operation.
|