非同步程式設計模型經歷了三代演進:APM(IAsyncResult)、EAP(事件基礎模式)與 TAP(async/await + Task)。Windows 8 Store Apps 採用 WinRT 非同步模式(EAP 變體),但完全相容 Task 體系。本文對比經典與現代模式,並詳細說明 IAsyncInfo 與 Task 雙向轉換技術。
IAsyncResult 模式 以 BeginXxx/EndXxx 配對方法為特徵,需手動管理回呼與狀態物件:
public class ClassicAsync {
private delegate string HelloDelegate(string name);
private readonly HelloDelegate _hello = name => {
Thread.Sleep(3000);
return "hello: " + name;
};
public IAsyncResult BeginRun(string name, AsyncCallback callback, object state) {
return _hello.BeginInvoke(name, callback, state);
}
public string EndRun(IAsyncResult ar) {
return _hello.EndInvoke(ar);
}
}
// 使用方式
var classic = new ClassicAsync();
IAsyncResult ar = classic.BeginRun("webabcd", ar => {
var result = classic.EndRun(ar);
// 需手動切回 UI 線程
Dispatcher.RunAsync(..., () => lbl.Text = result);
}, null);
缺點: 程式碼碎片化、例外處理分散、巢狀回呼地獄、無標準取消機制。
以 XxxAsync 方法 + XxxCompleted 事件為特徵,BackgroundWorker、WebClient 為典型代表。WinRT 非同步介面(IAsyncAction 等)可視為 EAP 的標準化演進。
async/await 配合 Task/Task<T> 是現代 .NET 非同步開發的標準:
// 無返回值
private async Task TaskWithoutReturn() {
await Task.Delay(1000); // 非阻塞等待
Interlocked.Increment(ref _count);
}
// 有返回值
private async Task TaskWithReturn() {
await Task.Delay(1000);
return Interlocked.Increment(ref _count);
}
// 並行執行多個 Task
await Task.WhenAll(TaskWithoutReturn(), TaskWithoutReturn(), TaskWithoutReturn());
// 不等待直接啟動(Fire-and-forget)
TaskWithoutAwait(); // 編譯器警告 CS4014,需刻意忽略
核心優勢: 線性程式碼結構、統一例外處理、自然的控制流、豐富的組合 API(WhenAll、WhenAny、Delay、FromResult 等)。
System.WindowsRuntimeSystemExtensions.AsTask 將 WinRT 非同步操作轉為 Task,支援取消權杖傳遞:
var action = AsyncInfo.Run(token => Task.Run(() => {
token.WaitHandle.WaitOne(3000);
token.ThrowIfCancellationRequested();
return 100;
}, token));
// 轉換為 Task,支援 CancellationToken
var task = action.AsTask(cts.Token);
int result = await task; // 自然 await
將 Task 包裝為 WinRT 介面,供 WinRT 元件或 JavaScript 呼叫:
var task = Task.Run(() => {
cts.Token.WaitHandle.WaitOne(3000);
cts.Token.ThrowIfCancellationRequested();
return 100;
}, cts.Token);
// 轉換為 IAsyncOperation
IAsyncOperation operation = task.AsAsyncOperation();
int result = await operation; // WinRT 消費者可直接 await
關鍵差異: Task 取消機制完善(CancellationToken),WinRT 介面取消較簡單(Cancel() 方法)。轉換時取消語意可能不完全對應。
| 維度 | APM (IAsyncResult) | EAP / WinRT | TAP (Task + async/await) |
|---|---|---|---|
| 程式碼風格 | 回呼巢狀 | 事件訂閱 | 線性同步風格 |
| 例外處理 | 分散在 EndXxx | Completed 事件參數 | try/catch 自然捕獲 |
| 取消支援 | 無標準 | IAsyncInfo.Cancel() | CancellationToken 完整體系 |
| 組合操作 | 極其困難 | 手動協調 | WhenAll/WhenAny 等豐富 API |
| 進度回報 | 自行實作 | WithProgress 介面 | IProgress<T> 標準介面 |
| 適用場景 | 舊版 API 相容 | WinRT 元件互操作 | 現代 .NET 應用開發首選 |
IAsyncInfo 轉換,無需手動 AsTask。IAsyncAction 等),內部實現用 Task 並 .AsAsyncOperation() 輸出。.Result、.Wait()、.GetResults(),死鎖高風險。理解三代非同步模型的演進脈絡與轉換技術,能讓你在 Windows 8 Store Apps 開發中游刃有餘地處理新舊代碼互操作與現代化重構。