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

C# 委派完整教學:從基礎語法到多播、非同步與實戰模式

     編輯:關於C語言

前言

委派是 C# 實現「函式即資料」的核心機制,也是事件、Lambda、LINQ、非同步程式設計的基石。本文系統整理委派宣告、實例化、多播、匿名方法、Lambda、泛型委派 (Func/Action)、非同步模式、以及常見設計模式應用。

1. 基礎語法


// 宣告委派型別:回傳 double,接受兩個 double 參數
delegate double BinaryOp(double x, double y);

static double Add(double x, double y) => x + y;
static double Sub(double x, double y) => x - y;

void Demo()
{
    // 實例化:方法群組轉換
    BinaryOp op = Add;
    double result = op(3, 5); // 8

    // 重新指派
    op = Sub;
    result = op(10, 4); // 6
}

2. 多播委派

委派可串聯多個目標方法,呼叫時依序執行,回傳值為最後一個方法的結果。


BinaryOp multi = Add;
multi += Sub; // 串聯
multi += (x, y) => x * y; // Lambda

double r = multi(10, 2); // 依序執行 Add(12)、Sub(8)、Mul(20) → 回傳 20

// 手動遍歷調用清單(取得所有回傳值)
foreach (BinaryOp d in multi.GetInvocationList())
{
    Console.WriteLine(d(10, 2)); // 12, 8, 20
}

3. 泛型委派:Func / Action / Predicate

.NET 內建常用委派,免去自訂宣告:

委派參數回傳用途
Action0void無參無回傳動作
Action<T>1void單參動作
Action<T1,T2>2void雙參動作
Func<TResult>0TResult無參函式
Func<T, TResult>1TResult單參函式
Func<T1,T2,TResult>2TResult雙參函式
Predicate<T>1bool條件判斷

Func op = (x, y) => x + y;
Action log = Console.WriteLine;
Predicate isEven = n => n % 2 == 0;

4. 匿名方法與 Lambda 演進


// C# 2.0 匿名方法
BinaryOp op1 = delegate(double x, double y) { return x + y; };

// C# 3.0 Lambda 運算式
BinaryOp op2 = (x, y) => x + y;              // 運算式主體
BinaryOp op3 = (x, y) => { return x + y; };  // 區塊主體

// 參數型別推論、單一參數可省略括號
Func square = x => x * x;
Action greet = () => Console.WriteLine("Hi");

5. 閉包:捕獲區域變數


void ClosureDemo()
{
    int factor = 10;
    Func multiply = n => n * factor; // 捕獲 factor

    factor = 20;
    Console.WriteLine(multiply(5)); // 100 (捕獲的是變數本身,非複製值)
}

陷阱:迴圈中捕獲迴圈變數會導致所有委派共用同一變數,需在迴圈內建立區域副本。

6. 非同步委派模式 (APM)

注意:現代 .NET 建議使用 Task.Run / async-await,此處僅作歷史架構維護參考。


delegate int LongRunningOp(int x);

LongRunningOp op = n => { Thread.Sleep(2000); return n * 2; };

// 啟動非同步
IAsyncResult ar = op.BeginInvoke(5, null, null);

// 1. 同步等待 (阻塞)
int result = op.EndInvoke(ar);

// 2. 輪詢
while (!ar.IsCompleted) Thread.Sleep(100);
result = op.EndInvoke(ar);

// 3. 回調
op.BeginInvoke(5, ar2 => {
    int r = op.EndInvoke(ar2);
    Console.WriteLine($"完成:{r}");
}, null);

7. 實戰設計模式應用

策略模式


interface IDiscountStrategy { decimal Calc(decimal price); }

class VipDiscount : IDiscountStrategy { public decimal Calc(decimal p) => p * 0.8m; }
class NormalDiscount : IDiscountStrategy { public decimal Calc(decimal p) => p * 0.95m; }

// 使用委派替代介面(輕量級策略)
Func vip = p => p * 0.8m;
Func normal = p => p * 0.95m;

decimal price = 100;
Console.WriteLine(vip(price)); // 80

觀察者模式 / 事件


class Publisher
{
    public event Action OnMessage; // 事件 = 封裝的多播委派

    public void Notify(string msg) => OnMessage?.Invoke(msg);
}

var pub = new Publisher();
pub.OnMessage += msg => Console.WriteLine($"Sub1: {msg}");
pub.OnMessage += msg => File.AppendAllText("log.txt", msg + Environment.NewLine);
pub.Notify("Hello");

管線/中介軟體模式


using Middleware = Func, Task>;

var pipeline = new List
{
    async (ctx, next) => { Console.WriteLine("Before 1"); await next(); Console.WriteLine("After 1"); },
    async (ctx, next) => { Console.WriteLine("Before 2"); await next(); Console.WriteLine("After 2"); }
};

Func end = () => Task.CompletedTask;
foreach (var mw in pipeline.Reverse())
{
    var next = end;
    end = () => mw(new HttpContext(), next);
}
await end();

8. 常見陷阱與最佳實踐

陷阱說明解法
迴圈閉包foreach/for 變數被共用迴圈內建立區域變數 var copy = item;
事件記憶體洩漏訂閱者未取消訂閱,導致無法 GC實作 IDisposable 取消訂閱,或使用弱事件模式
多執行緒調用清單變動遍歷時其他執行緒 +=/-=先 var list = del.GetInvocationList(); 再遍歷副本
例外中斷多播鏈前一個方法拋出例外,後續不執行手動遍歷 GetInvocationList() 包裝 try-catch

總結

委派是 C# 函數式程式設計的入口:

  1. 型別安全的函式指標,支援實例/靜態方法、Lambda、匿名方法。
  2. 多播 天然實現觀察者、管線、策略等模式。
  3. 標準委派 Func/Action/Predicate 涵蓋 99% 場景,優先使用。
  4. 非同步 棄用 Begin/EndInvoke,全面擁抱 Task/async-await。
  5. 閉包 強大但需警惕變數捕獲語意,特別在迴圈與多執行緒中。

熟練運用委派,能讓程式碼更靈活、可測試、符合開放封閉原則,是邁向高階 C# 開發者的關鍵技能。

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