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

相关推荐
北冥湖畔的燕雀3 小时前
C++泛型编程(函数模板以及类模板)
开发语言·c++
QX_hao4 小时前
【Go】--map和struct数据类型
开发语言·后端·golang
你好,我叫C小白4 小时前
C语言 循环结构(1)
c语言·开发语言·算法·while·do...while
Evand J6 小时前
【MATLAB例程】基于USBL和DVL的线性回归误差补偿,对USBL和DVL导航数据进行相互补偿,提高定位精度,附代码下载链接
开发语言·matlab·线性回归·水下定位·usbl·dvl
爱喝白开水a7 小时前
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板_langchain prompt
开发语言·数据库·人工智能·python·langchain·prompt·知识图谱
Neverfadeaway7 小时前
【C语言】深入理解函数指针数组应用(4)
c语言·开发语言·算法·回调函数·转移表·c语言实现计算器
武子康7 小时前
Java-152 深入浅出 MongoDB 索引详解 从 MongoDB B-树 到 MySQL B+树 索引机制、数据结构与应用场景的全面对比分析
java·开发语言·数据库·sql·mongodb·性能优化·nosql
杰克尼7 小时前
JavaWeb_p165部门管理
java·开发语言·前端
一成码农7 小时前
JavaSE面向对象(下)
java·开发语言
偶尔的鼠标人8 小时前
Avalonia DataGrid 控件的LostFocus事件会多次触发
开发语言·c#