发布于2026-07-18 阅读(0)
扫一扫,手机访问
多播委托赋值必须用+=而非=,否则覆盖原有方法;调用前需用?.判空;移除时方法引用须完全一致;异常会中断后续调用,需手动遍历+try/catch处理。

直接拿 = 赋值,等于把之前的委托全都扔了,这不是追加,这是替换。C# 的多播委托底层其实是个链表,只有 += 才能把多个方法“缝合”到同一个委托实例上。
一个常见翻车现场:
myDelegate = MethodA; myDelegate = MethodB; myDelegate(); // 只调了 MethodB,MethodA 没了
正确的姿势是:
Action handler = null; handler += MethodA; handler += MethodB; handler(); // 依次调用 MethodA → MethodB
+= 背后其实是 Delegate.Combine,自动帮你处理空值和类型检查null,+= 也能安全初始化,不用提前判空Delegate.Combine(a, b),容易出错,可读性也差就算你刚用 += 加过方法,也别拍胸脯说 handler 一定非空——万一所有订阅者都用 -= 撤了,或者初始就是 null,那直接调用就炸了。
错误示范:handler(); —— 运行时直接给你一个 NullReferenceException。
安全写法(推荐):
handler?.Invoke();
?. 是 C# 6.0+ 引入的空条件操作符,写法简洁,而且比 if (handler != null) handler(); 更靠谱(线程安全考虑)handler?.Invoke() 外面套一层 try/catch——异常是设计缺陷,不是流程分支Func),?. 会返回 null 或默认值,需要根据场景单独处理-= 不是模糊匹配,它严格比较方法指针,连闭包捕获的变量都得一模一样。稍微差一点,移除就失败,结果就是内存泄漏或者方法重复执行。
典型陷阱:
handler += () => Console.WriteLine("A");
handler -= () => Console.WriteLine("A"); // ❌ 失败!这是另一个匿名方法实例
handler += MethodA; handler -= MethodA;var lambda = () => ...; handler += lambda; handler -= lambda;Action 或 Func<> 时,不要在循环里反复创建新委托实例然后又移除,那是给自己挖坑这是最容易被忽略的设计事实:一旦某个订阅方法抛了异常,整个链就停了,后面的方法永远没机会执行。
比如:
handler += () => { Console.Write("1"); };
handler += () => { throw new Exception(); };
handler += () => { Console.Write("3"); }; // ❌ 永远不会执行
GetInvocationList() + 手动 try/catchforeach (var d in handler.GetInvocationList()) { try { d.DynamicInvoke(); } catch { /* 忽略或记录 */ } }DynamicInvoke 比直接 Invoke 慢一个数量级,高频场景要慎用多播委托不是简单的“语法糖”,它的调用顺序、异常传播、生命周期管理全由底层 Delegate 类控制。写的时候少想“链式”,多想“事件队列”——每个环节都得自己兜底。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8