1. 委托的基本概念
-
定義:委托是一種類型安全的函數指針,用于封裝方法(靜態方法或實例方法)。
-
核心作用:允許將方法作為參數傳遞,實現回調機制和事件處理。
-
類型安全:委托在編譯時會檢查方法簽名(參數類型和返回值類型)。
2. 委托的聲明與使用
-
聲明語法:
delegate [返回類型] DelegateName([參數列表]);
?示例:
delegate void MyDelegate(string message); // 無返回值,接受一個字符串參數
- 實例化與調用:
// 實例化委托(綁定方法)
MyDelegate del = new MyDelegate(MyMethod);// 調用委托
del("Hello");static void MyMethod(string msg) {Console.WriteLine(msg);
}
3. 多播委托(Multicast Delegate)
-
特點:一個委托實例可以綁定多個方法,通過?
+=
?和?-=
?運算符管理方法鏈。 -
調用順序:按添加順序依次執行所有方法。
-
返回值:若委托有返回值,只有最后一個方法的返回值會被保留。
MyDelegate del1 = Method1;
MyDelegate del2 = Method2;
MyDelegate combined = del1 + del2; // 合并委托
combined("Multi-cast"); // 依次調用 Method1 和 Method2combined -= del1; // 移除委托
-
4.?匿名方法與Lambda表達式?
- 匿名方法(C# 2.0):無需顯式定義方法,直接通過?
delegate
?關鍵字綁定。
MyDelegate del = delegate(string msg) {Console.WriteLine("Anonymous: " + msg);
};
- Lambda表達式(C# 3.0+):簡化匿名方法的語法。
MyDelegate del = (msg) => Console.WriteLine("Lambda: " + msg);
5. 內置泛型委托
Action
:無返回值的委托,最多支持16個參數。
Action<string> action = (s) => Console.WriteLine(s);
Func
:有返回值的委托,最后一個泛型參數為返回值類型,最多支持16個參數(不包括返回值類型)。
Func<int, int, int> add = (a, b) => a + b;
int result = add(3, 5); // 返回8
Predicate
:返回?bool
?的委托,常用于條件判斷,僅支持一個參數。
Predicate<int> isEven = num => num % 2 == 0;
bool result = isEven(4); // 返回true
6. 委托與事件
-
事件本質:事件是基于委托的封裝,提供更安全的訂閱/取消訂閱機制。
-
事件聲明:
public event EventHandler MyEvent; // EventHandler 是內置委托
- 觸發事件:
MyEvent?.Invoke(this, EventArgs.Empty); // 安全調用
- 事件與委托的區別:事件不能在類外部賦值和調用,只能在聲明它的類內部觸發(
Invoke
),外部只能訂閱(+=
)或取消訂閱(-=
)。
7. 協變與逆變(Covariance & Contravariance)
- 協變(Covariance):允許委托返回類型是派生類(更具體類型)。(父類泛型委托裝子類泛型委托)
delegate Animal GetAnimalDelegate();
GetAnimalDelegate del = GetDog; // Dog 是 Animal 的子類
Animal animal = del();static Dog GetDog() => new Dog();
- 逆變(Contravariance):允許委托參數是基類(更通用類型)。(子類泛型委托裝父類泛型委托)
delegate void ProcessDogDelegate(Dog dog);
ProcessDogDelegate del = ProcessAnimal; // 參數類型為Animal(基類)
del(new Dog());static void ProcessAnimal(Animal animal) { }
8. 注意事項
-
內存泄漏:長期持有委托可能導致對象無法釋放,需及時取消訂閱(
-=
)。 -
線程安全:多線程中委托調用需確保線程同步。
-
默認值處理:調用空委托會引發異常,需判空:
del?.Invoke("Hello");