C Sharp 多播委托
外观
多播委托(Multicast Delegate)是C#中一种特殊的委托类型,能够同时引用多个方法,并按顺序调用它们。它是事件处理系统和观察者模式的核心实现机制。
基本概念[编辑 | 编辑源代码]
在C#中,委托本质上是类型安全的函数指针。多播委托则通过组合多个委托实例,形成一个调用列表(invocation list)。当多播委托被调用时,列表中的所有方法会按照添加顺序依次执行。
与单播委托的区别[编辑 | 编辑源代码]
- 单播委托:仅能绑定一个方法
- 多播委托:通过
+=
和-=
运算符组合多个方法
语法与使用[编辑 | 编辑源代码]
多播委托使用System.Delegate
的Combine
和Remove
方法(或对应的运算符)来管理调用列表。
// 声明委托
public delegate void MessageHandler(string message);
class Program
{
static void Main()
{
// 创建委托实例
MessageHandler handler = ShowMessage;
// 多播委托组合
handler += FormatMessage;
handler += LogMessage;
// 调用多播委托
handler("Hello World");
// 移除委托
handler -= LogMessage;
handler("After removal");
}
static void ShowMessage(string msg) => Console.WriteLine($"显示: {msg}");
static void FormatMessage(string msg) => Console.WriteLine($"格式化: {msg.ToUpper()}");
static void LogMessage(string msg) => Console.WriteLine($"日志: {DateTime.Now}: {msg}");
}
输出结果:
显示: Hello World 格式化: HELLO WORLD 日志: 2023-11-15 10:00:00: Hello World 显示: After removal 格式化: AFTER REMOVAL
执行流程[编辑 | 编辑源代码]
多播委托的执行遵循以下规则: 1. 按添加顺序同步执行 2. 如果委托有返回值,只返回最后一个方法的返回值 3. 如果任一方法抛出异常,后续方法不会执行
数学表示[编辑 | 编辑源代码]
多播委托可以表示为方法的有序集合: 调用时相当于函数组合:
实际应用案例[编辑 | 编辑源代码]
事件处理系统[编辑 | 编辑源代码]
多播委托是C#事件的基础实现:
public class Button
{
public event EventHandler Clicked;
public void SimulateClick()
{
Clicked?.Invoke(this, EventArgs.Empty);
}
}
class Program
{
static void Main()
{
Button btn = new Button();
btn.Clicked += OnButtonClick1;
btn.Clicked += OnButtonClick2;
btn.SimulateClick();
}
static void OnButtonClick1(object sender, EventArgs e)
=> Console.WriteLine("按钮点击处理1");
static void OnButtonClick2(object sender, EventArgs e)
=> Console.WriteLine("按钮点击处理2");
}
中间件管道[编辑 | 编辑源代码]
在ASP.NET Core等框架中,多播委托用于构建请求处理管道:
public delegate Task RequestDelegate(HttpContext context);
public class MiddlewarePipeline
{
private RequestDelegate _pipeline;
public void Configure()
{
_pipeline = LogRequest;
_pipeline += Authenticate;
_pipeline += ProcessRequest;
}
public async Task Run(HttpContext context) => await _pipeline(context);
// 各中间件方法...
}
高级主题[编辑 | 编辑源代码]
委托组合[编辑 | 编辑源代码]
可以使用Delegate.Combine
显式组合委托:
Delegate d1 = new MessageHandler(ShowMessage);
Delegate d2 = new MessageHandler(FormatMessage);
Delegate combined = Delegate.Combine(d1, d2);
异常处理[编辑 | 编辑源代码]
建议在多播委托调用时处理异常:
foreach(Delegate handler in multicastDelegate.GetInvocationList())
{
try {
handler.DynamicInvoke(args);
}
catch(Exception ex) {
// 处理异常
}
}
最佳实践[编辑 | 编辑源代码]
- 避免在多播委托中使用有返回值的方法
- 考虑使用
GetInvocationList()
单独调用每个委托 - 事件处理中应检查委托是否为null
- 注意内存泄漏问题,及时移除不需要的委托
性能考虑[编辑 | 编辑源代码]
多播委托调用比直接方法调用稍慢,因为需要: 1. 遍历调用列表 2. 进行额外的类型检查 3. 可能需要装箱/拆箱操作
对于性能敏感场景,可以考虑缓存委托实例或使用其他设计模式。