IAsyncResult 是 APM (Asynchronous Programming Model) 的核心協定物件,串聯 BeginXXX 傳回與 EndXXX 參數。本文詳細解析其介面成員、AsyncResult 實作細節、AsyncWaitHandle 三大同步等待策略,並附上 Jeffrey Richter PowerThreading 庫中的自訂 AsyncResult<T> 實作參考。
| 屬性 | 用途 |
|---|---|
AsyncWaitHandle | 取得 WaitHandle,供同步等待 |
IsCompleted | 非同步作業是否已完成 |
AsyncState | 使用者自訂狀態物件 (BeginXXX 最後一參數) |
CompletedSynchronously | 是否同步完成 (極少用) |
AsyncDelegate:取得原始委派物件,供 EndInvoke 使用。EndInvokeCalled:偵測是否已呼叫 EndInvoke。delegate decimal SalaryHandler(decimal salary, int months, decimal bonus);
SalaryHandler del = obj.YearlySalary;
IAsyncResult ar = del.BeginInvoke(100000, 15, 100000, OnCallback, 2000m);
DoOtherWork(); // 主執行緒繼續執行
void OnCallback(IAsyncResult ar)
{
decimal extra = (decimal)ar.AsyncState; // 2000
SalaryHandler del = (SalaryHandler)((AsyncResult)ar).AsyncDelegate;
decimal result = del.EndInvoke(ar); // 取得回傳值
Console.WriteLine(result + extra);
}
ar.AsyncWaitHandle.WaitOne(); // 封鎖直到完成
// 或 WaitOne(timeout) 限時等待
WaitHandle[] handles = { ar1.AsyncWaitHandle, ar2.AsyncWaitHandle };
WaitHandle.WaitAll(handles); // 等待最慢者完成
WaitHandle.WaitAny(handles); // 等待最快者完成
EndInvoke 後 WaitHandle 不會自動關閉,需手動釋放:
ar.AsyncWaitHandle.Close(); // 在 EndInvoke 後呼叫
IAsyncResult,使用 Interlocked.Exchange 原子更新狀態,ManualResetEvent 實作 AsyncWaitHandle。TResult m_result 與強型別 EndInvoke()。BeginDoTask/EndDoTask 封裝耗時工作,內部使用 ThreadPool.QueueUserWorkItem 執行,完成時呼叫 SetAsCompleted。

掌握 IAsyncResult 與 WaitHandle,即可精確控制非同步流程的同步點、逾時與取消,是進階非同步程式設計的基石。