首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

.NET 3.5 環境下的 C# 非同步程式設計框架實作

     編輯:關於C語言

在 .NET Framework 4.0 推出 Task 與平行運算庫(TPL)之前,開發者若身處 .NET 3.5 專案環境,要實現非同步操作往往只能仰賴傳統的 BeginInvoke/EndInvoke 模式(APM)。本文將示範如何封裝一套輕量級的非同步程式框架,提供類似 Task.ContinueWith 的鏈式呼叫、例外處理、集合平行處理等功能,讓舊專案也能享受現代化的非同步開發體驗。

核心架構設計

框架由四大核心類別組成,分工明確:

  • Operator(抽象基類):定義非同步作業的通用契約,包含啟動、等待、回呼、例外捕捉與鏈式延續。
  • ActionAsync:封裝無回傳值的 Action 委派。
  • FuncAsync<TResult>:封裝有回傳值的 Func<TResult> 委派。
  • Asynchronous(靜態門面):提供 Invoke、WaitAll、Foreach、ContinueWithAsync 等便利方法,對外隱藏細節。

介面契約

public interface IOperationAsync
{
    IAsyncResult Invoke();           // 啟動非同步作業
    void Wait();                     // 同步等待完成
    void CompletedCallBack(IAsyncResult ar); // 完成回呼
    void CatchException(Exception ex);       // 例外捕捉
}

public interface IContinueWithAsync
{
    Operator Previous { get; set; }  // 上一個作業
    Operator Next { get; set; }      // 下一個作業
    Operator ContinueWithAsync(Action action);
    Operator ContinueWithAsync<TParameter>(Action<TParameter> action, TParameter parameter);
    Operator ContinueWithAsync<TResult>(Func<TResult> func);
    Operator ContinueWithAsync<TParameter, TResult>(Func<TParameter, TResult> func, TParameter parameter);
}

Operator 基類實作重點

Operator 同時實作上述兩個介面,內部持有 IAsyncResult Middle 作為目前作業的狀態控制代碼。關鍵邏輯如下:

  • Wait():若作業未完成,呼叫 AsyncWaitHandle.WaitOne() 封鎖執行緒。
  • ContinueWithAsync 系列方法:建立下一個 Operator(ActionAsync 或 FuncAsync),設定 Previous/Next 雙向連結,並回傳新節點以支援鏈式語法。
  • ContinueAsync():在回呼完成時自動啟動 Next.Invoke(),實現自動延續。

ActionAsync 與 FuncAsync 具體實作

兩者皆繼承 Operator,差別在於委派型別與結果處理:

  • ActionAsync:以 _action.BeginInvoke(CompletedCallBack, null) 啟動,回呼中呼叫 EndInvoke 並觸發 ContinueAsync()。
  • FuncAsync<TResult>:實作 IFuncOperationAsync<TResult>,回呼中以 _func1.EndInvoke(ar) 取得回傳值,透過 SetResult 保存,GetResult() 內部會先 Wait() 確保完成再回傳。

Asynchronous 靜態門面:常用操作一覽

方法用途
Invoke(Action)啟動無參數無回傳非同步作業
Invoke<T>(Action<T>, T)啟動帶單一參數的 Action
Invoke<TResult>(Func<TResult>)啟動無參數有回傳非同步作業
WaitAll(IEnumerable<Operator>)阻塞直到所有作業完成
WaitAny(IEnumerable<Operator>)輪詢等待任一作業完成
Foreach<T>(IEnumerable<T>, Action<T>)對集合每個元素平行啟動 Action,回傳 Operator 集合
ContinueWithAsync(operators, action)在指定作業群全部完成後延續執行

實戰範例

1. 基本 Fire-and-Forget

Asynchronous.Invoke(() => Console.WriteLine("背景作業執行中..."));

2. 有回傳值的非同步呼叫

var op = Asynchronous.Invoke(() => ComputeHeavy());
op.Wait();
Console.WriteLine($"結果:{((FuncAsync<int>)op).Result}");

3. 集合平行處理 + 統一等待

int[] data = {1,2,3,4,5};
var ops = Asynchronous.Foreach(data, x => x * 2); // 平行啟動
Asynchronous.WaitAll(ops);                        // 等全部完成
Asynchronous.Foreach(ops.Cast<FuncAsync<int,int>>(), 
                     o => Console.WriteLine(o.Result));

4. 鏈式延續

Asynchronous.Invoke(Console.WriteLine, 1)
    .ContinueWithAsync(Console.WriteLine, 2)
    .ContinueWithAsync(Console.WriteLine, 3);
// 依序輸出 1, 2, 3

5. 逐項完成即時通知

var ops = Asynchronous.Foreach(data, x => x * 2);
Asynchronous.Foreach(ops, o => 
    o.ContinueWithAsync(() => 
    {
        if (o.Exception != null) 
            LogError(o.Exception);
        else 
            Console.WriteLine($"項目完成:{((FuncAsync<int,int>)o).Result}");
    }));

已知限制與注意事項

  • ContinueWithAsync 回傳的 Operator 若直接呼叫 Wait(),僅會等待該節點本身,不會自動往前追溯;建議將所有需等待的作業收集後統一 WaitAll。
  • 框架基於 ThreadPool 執行,高併發場景下請自行評估執行緒池壓力,或搭配 SemaphoreSlim 限制平行度。
  • 例外會被封裝在各 Operator.Exception 屬性,不會自動向上拋出,務必在延續或最後統一檢查。

結語

這套框架雖無法取代 .NET 4.0+ 的 Task/async-await,但在受限於 .NET 3.5 的存續專案中,能以極低成本引入現代化的非同步模式:啟動、等待、延續、集合平行、例外集中處理一應俱全。若團隊規劃遷移至新版框架,程式碼結構也極易對應至 Task.Run、Task.WhenAll、ContinueWith,遷移成本極低。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved