C#事件访问器(Event)

事件介绍

和委托类似,事件是后期绑定机制。 实际上,事件是建立在对委托的语言支持之上的。

事件是对象用于(向系统中的所有相关组件)广播已发生事情的一种方式。 任何其他组件都可以订阅事件,并在

事件引发时得到通知。

通过订阅事件,还可在两个对象(事件源和事件接收器)之间创建耦合。 需要确保当不再对事件感兴趣时,事件接

收器将从事件源取消订阅。

事件的访问器作用

涉及到线程安全的事件添加和移除操作。其作用是确保在多线程环境下对事件处理程序的添加和移除是安全的。具体来说:

  1. 线程安全 :使用 Interlocked.CompareExchange 确保在多个线程同时操作事件处理程序时,不会导致数据竞争或更新不一致的问题。

  2. 添加处理程序add 访问器将新的处理程序添加到事件中,通过 Delegate.Combine 合并现有的处理程序和新的处理程序。

  3. 移除处理程序remove 访问器从事件中移除指定的处理程序,通过 Delegate.Remove 从现有处理程序列表中移除目标处理程序。

演示如何实现自定义的 add 和 remove 事件访问器。 虽然可以替换访问器内的任何代码,但建议先锁定事件,再添加或删除新的事件处理程序方法。

cs 复制代码
event EventHandler IDrawingObject.OnDraw
{
    add
    {
        lock (objectLock)
        {
            PreDrawEvent += value;
        }
    }
    remove
    {
        lock (objectLock)
        {
            PreDrawEvent -= value;
        }
    }
}

下面这个示范的事件访问器是我再写tcp通讯的时候用到的,因为代码比较多就列举了一个接收事件

cs 复制代码
 private MyModbusSlave.ReceviceByteEventHandler _ReceviceByteEventHandler;

 public delegate void ReceviceByteEventHandler(byte[] date);


//确保在多个线程同时进行事件处理程序的添加和移除时,操作是线程安全的。这种实现方式可以防止数据竞争和并发问题。
[Category("ModbusTcp事件")]
[Description("接收Byte数据事件")]
public event ReceviceByteEventHandler OnReceviceByte
{
    add
    {
        //取得当前事件处理程序列表的副本。_ReceviceByteEventHandler 是存储事件处理程序的字段。
        ReceviceByteEventHandler receviceByteEventHandler = this._ReceviceByteEventHandler;
        //临时变量,用于在更新事件处理程序时进行比较。
        ReceviceByteEventHandler temp;
        //使用 do-while 循环来确保事件处理程序的更新是原子性的。如果在更新过程中,事件处理程序的列表被其他线程修改了,Interlocked.CompareExchange 将返回修改后的值,循环会重新尝试更新。
        do
        {
            temp = receviceByteEventHandler;
            //使用 Delegate.Combine 将新的处理程序 value 添加到当前事件处理程序列表中,并返回更新后的事件处理程序列表。
            ReceviceByteEventHandler value2 = (ReceviceByteEventHandler)Delegate.Combine(receviceByteEventHandler);
            //尝试将 _ReceviceByteEventHandler 更新为 value2。如果 _ReceviceByteEventHandler 的值等于 temp(表示在此期间没有其他线程修改事件处理程序列表),则更新成功。
            receviceByteEventHandler = Interlocked.CompareExchange(ref _ReceviceByteEventHandler, value2, temp);
        } while (receviceByteEventHandler != temp);
    }
    //取得当前事件处理程序列表的副本。
    remove
    {
        ReceviceByteEventHandler receviceByteEventHandler = this._ReceviceByteEventHandler;
        ReceviceByteEventHandler temp;
        do
        {
            temp = receviceByteEventHandler;
            //使用 Delegate.Remove 从当前事件处理程序列表中移除指定的处理程序 value,并返回更新后的事件处理程序列表。
            ReceviceByteEventHandler value2 = (ReceviceByteEventHandler)Delegate.Remove(temp, value);
            receviceByteEventHandler = Interlocked.CompareExchange(ref _ReceviceByteEventHandler, value2, temp);
        } while (receviceByteEventHandler != temp);
    }
}

通过 Interlocked.CompareExchangeDelegate.Combine / Delegate.Remove 实现了线程安全的事件处理程序添加和移除操作。这样可以避免在多线程环境下因并发修改事件处理程序列表而导致的问题,确保事件的处理程序在多个线程中正确地添加和移除。

什么情况下不使用事件访问器

在不使用这种线程安全的事件访问器的情况下,你可能会面临多线程环境下的竞态条件和数据一致性问题。

如果你的应用程序只在单线程环境下运行,或者你能够确保事件的添加和移除操作不会发生在多个线程之间的竞争,那么你可以不使用这种线程安全的实现。

但在大多数情况下,尤其是在复杂的多线程应用中,保持线程安全是很重要的,建议继续使用这种方式来避免潜在的问题。

想要更详细的了解和学习事件可以去这里:

如何实现自定义事件访问器 - C# | Microsoft Learn

相关推荐
Kisorge24 分钟前
【C语言】指针数组、数组指针、函数指针、指针函数、函数指针数组、回调函数
c语言·开发语言
轻口味1 小时前
命名空间与模块化概述
开发语言·前端·javascript
晓纪同学2 小时前
QT-简单视觉框架代码
开发语言·qt
威桑2 小时前
Qt SizePolicy详解:minimum 与 minimumExpanding 的区别
开发语言·qt·扩张策略
飞飞-躺着更舒服2 小时前
【QT】实现电子飞行显示器(简易版)
开发语言·qt
明月看潮生3 小时前
青少年编程与数学 02-004 Go语言Web编程 16课题、并发编程
开发语言·青少年编程·并发编程·编程与数学·goweb
明月看潮生3 小时前
青少年编程与数学 02-004 Go语言Web编程 17课题、静态文件
开发语言·青少年编程·编程与数学·goweb
Java Fans3 小时前
C# 中串口读取问题及解决方案
开发语言·c#
盛派网络小助手3 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#
码农君莫笑3 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio