C# 委托链实现方法 C#如何使用+=和-=操作委托

来源:这里教程网 时间:2026-02-21 17:40:54 作者:

委托链本质是多播委托

在 C# 中,用

+=
给委托变量添加方法,不是简单地覆盖,而是把新方法追加到内部调用列表里——这个结构叫「多播委托」(MulticastDelegate)。只要委托类型签名一致,就能链式叠加。但要注意:
void
返回值的委托才能安全组成链;如果委托返回非
void
类型,调用链时只会拿到最后一个方法的返回值,前面的全被丢弃。

+= 和 -= 实际调用 Delegate.Combine 和 Delegate.Remove

编译器把

+=
编译成
Delegate.Combine
-=
编译成
Delegate.Remove
。这意味着:

+=
不会重复添加相同方法实例(基于引用相等判断)
-=
只移除第一个匹配的方法实例,不是全部
如果尝试移除一个从未添加过的方法,不会报错,只是静默忽略 委托链为空时,变量值为
null
,直接调用会抛
NullReferenceException

常见陷阱:匿名函数和闭包导致移除失败

下面这段代码看似能成功移除,实则无效:

Action action = () => Console.WriteLine("A");
action += () => Console.WriteLine("B");
action -= () => Console.WriteLine("B"); // ❌ 不起作用!

原因:每次写

() => ...
都创建了新的委托实例,内存地址不同。
Delegate.Remove
找不到原对象。正确做法是保留对要移除方法的引用:

Action b = () => Console.WriteLine("B");
action += b;
action -= b; // ✅ 成功

调用委托链时异常会中断后续执行

委托链是顺序同步执行的。一旦某个方法抛出未捕获异常,后面的委托将完全跳过。没有内置的“继续执行下一个”的机制。若需容错,必须手动遍历

GetInvocationList()
并 try/catch 每一项:

foreach (Action a in action.GetInvocationList())
{
    try { a(); }
    catch { /* 忽略或记录 */ }
}

这也意味着,别依赖委托链做关键路径的串行任务协调——它不是工作队列,也没有事务性。

委托链看起来简洁,但它的生命周期管理、异常传播、引用一致性都容易出隐性问题。真要构建事件系统或回调调度,优先考虑

event
关键字封装,或直接用
System.Collections.Generic.List<action></action>
显式控制。

相关推荐