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

相关推荐
o独酌o11 分钟前
递归的‘浅’理解
java·开发语言
Book_熬夜!14 分钟前
Python基础(六)——PyEcharts数据可视化初级版
开发语言·python·信息可视化·echarts·数据可视化
m0_6312704041 分钟前
高级c语言(五)
c语言·开发语言
2401_858286111 小时前
53.【C语言】 字符函数和字符串函数(strcmp函数)
c语言·开发语言
程序猿练习生1 小时前
C++速通LeetCode中等第5题-无重复字符的最长字串
开发语言·c++·leetcode
2401_858120261 小时前
MATLAB中的无线通信系统部署和优化工具有哪些
开发语言·matlab
MATLAB滤波1 小时前
【PSINS】基于PSINS工具箱的EKF+UKF对比程序|三维定位|组合导航|MATLAB
开发语言·matlab
2401_858120531 小时前
MATLAB在嵌入式系统设计中的最佳实践
开发语言·matlab
蓝裕安1 小时前
伪工厂模式制造敌人
开发语言·unity·游戏引擎
无名之逆2 小时前
云原生(Cloud Native)
开发语言·c++·算法·云原生·面试·职场和发展·大学期末