在 C# 开发中,委托(Delegate)和事件(Event)是实现回调机制、解耦组件的重要工具。然而,当程序进入多线程环境时,如果不加以注意,很容易引发空引用异常(NullReferenceException)或竞态条件(Race Condition)。本文将手把手教你如何安全地在多线程场景下使用委托与事件,确保你的 C# 应用稳定可靠。

简单来说:
在单线程程序中,事件触发前检查是否为 null 即可:
if (MyEvent != null){ MyEvent(this, EventArgs.Empty);}但在多线程环境下,可能在你检查 MyEvent != null 之后、调用之前,另一个线程取消了所有订阅(即事件变为 null),导致调用时抛出异常。这就是典型的竞态条件。
这是 .NET 官方推荐的做法,利用委托的不可变性(每次 += 或 -= 都会创建新实例),通过局部变量避免竞态:
// 定义事件public event EventHandler MyEvent;// 安全触发事件protected virtual void OnMyEvent(){ // 将事件引用复制到局部变量 EventHandler handler = MyEvent; // 局部变量不会被其他线程修改 if (handler != null) { handler(this, EventArgs.Empty); }}这种方法简洁高效,适用于绝大多数场景,也是 C#委托线程安全 的最佳实践之一。
从 C# 6 开始,可以使用 ?. 运算符简化代码:
protected virtual void OnMyEvent(){ MyEvent?.Invoke(this, EventArgs.Empty);}编译器会自动将其转换为类似局部变量的方式,因此同样具备 C#事件线程安全 特性。
虽然可以通过 lock 保证线程安全,但通常不推荐,因为会带来性能开销,并可能导致死锁:
private readonly object _lockObj = new object();protected virtual void OnMyEvent(){ lock (_lockObj) { if (MyEvent != null) { MyEvent(this, EventArgs.Empty); } }}除非你有非常特殊的同步需求,否则优先选择前两种方法。
using System;using System.Threading.Tasks;class Publisher{ public event EventHandler StatusChanged; protected virtual void OnStatusChanged() { // 推荐方式:局部变量 EventHandler handler = StatusChanged; handler?.Invoke(this, EventArgs.Empty); } public void DoWork() { // 模拟异步工作 Task.Run(() => { System.Threading.Thread.Sleep(1000); OnStatusChanged(); // 安全线程调用 }); }}class Program{ static void Main() { var pub = new Publisher(); pub.StatusChanged += (sender, e) => Console.WriteLine("状态已更新!"); pub.DoWork(); Console.ReadLine(); }}在多线程环境中使用 C# 委托与事件时,务必注意 多线程委托调用 的安全性。记住以下要点:
?. 语法糖(C# 6+);掌握这些技巧后,你就能写出健壮、可靠的 C#线程安全事件处理 代码,无论是在 WinForms、WPF 还是 ASP.NET Core 中都能游刃有余。
希望这篇教程能帮助你彻底理解 C# 委托与事件的线程安全问题。欢迎分享给更多开发者!
本文由主机测评网于2025-12-21发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://vpshk.cn/20251211002.html