声明语法:
csharppublic delegate void MyDelegate(string message);
实例化与调用:
csharpMyDelegate del = new MyDelegate(MethodName);
del("Hello, World!");
+=
运算符添加方法。-=
运算符移除方法。事件:是对委托的封装,用于发布-订阅模式,提供更安全的访问机制。
声明事件:
csharppublic event MyDelegate MyEvent;
触发事件:
csharpMyEvent?.Invoke("Event triggered");
Action:表示无返回值的方法。
csharpAction<string> action = Console.WriteLine;
Func:表示有返回值的方法。
csharpFunc<int, int, int> add = (x, y) => x + y;
匿名方法:使用 delegate
关键字定义匿名方法。
csharpMyDelegate del = delegate(string msg) { Console.WriteLine(msg); };
Lambda 表达式:简化的匿名方法写法。
csharpMyDelegate del = msg => Console.WriteLine(msg);
声明事件:
csharppublic event EventHandler MyEvent;
订阅事件:
csharpMyEvent += new EventHandler(MyEventHandler);
触发事件:
csharpMyEvent?.Invoke(this, EventArgs.Empty);
定义自定义参数类:
csharppublic class MyEventArgs : EventArgs
{
public string Message { get; set; }
}
声明带有自定义参数的事件:
csharppublic event EventHandler<MyEventArgs> MyEvent;
触发事件并传递参数:
csharpMyEvent?.Invoke(this, new MyEventArgs { Message = "Hello" });
事件只能由声明它的类触发,外部类只能订阅或取消订阅事件,不能触发事件。
事件在多线程执行和异步调用时可能出现的问题
NullReferenceException(空引用异常)
csharpMyEvent?.Invoke(this, EventArgs.Empty);
如果在判断 MyEvent != null
后,另一个线程刚好将所有订阅者移除,会导致 MyEvent
在调用时变为 null,从而抛出异常。
委托调用执行异常或遗漏
当多个线程同时执行:
csharpMyEvent += HandlerA; MyEvent += HandlerB;
这可能破坏底层的委托链,导致:
一般框架中都会封装好事件系统,避免我们手动调用导致的线程安全的问题,比如GameFramework
csharpEventHandler handler = MyEvent;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
csharpMyEvent?.Invoke(this, EventArgs.Empty);
对比项 | 委托(Delegate) | 事件(Event) |
---|---|---|
本质 | 类型安全的函数指针(封装方法引用) | 基于委托的封装机制 |
语法定义 | public delegate void MyDelegate(); | public event MyDelegate MyEvent; |
访问权限 | 可被外部代码直接调用、赋值、清空,不安全 | 外部代码只能 += 或 -= 订阅与取消,不能调用 |
调用方式 | 外部和内部代码都可以调用 | 只能在声明它的类内部调用 |
封装性 | 无封装(委托字段是公开变量) | 提供了封装(事件只能通过订阅机制访问) |
多播支持 | 支持(委托可组合多个方法) | 支持(事件本质是多播委托) |
使用场景 | 回调、策略模式、函数链式调用 | 发布-订阅模式(UI 事件、系统事件、状态通知) |
默认线程安全 | ❌ 否,操作需自行加锁或复制引用 | ❌ 否,同样需加锁或拷贝引用触发 |
是否必须依赖 | 独立存在 | 必须基于委托类型 |
💡 总结:事件是对委托的进一步封装,用于发布-订阅模型,限制外部随意触发调用,使程序结构更安全、清晰。
本文作者:xuxuxuJS
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!