c# - C#中事件的内部设计

标签 c#

刚读完 Jon Skeet 的 article about events and delegates并提出一个问题。

让我们先在代码中声明一个事件

public event EventHandler MyEvent

然后我想通过某种方式在代码中提出来

if (MyEvent != null)
    Myevent(this,EvtArgs.Empty);

Jon 说实际上 MyEvent 看起来像这样:

private EventHandler _myEvent;

public event EventHandler MyEvent
{
    add
    {
        lock (this)
        {
            _myEvent += value;
        }
    }
    remove
    {
        lock (this)
        {
            _myEvent -= value;
        }
    }        
} 

问题是当我比较 MyEvent != null 时到底发生了什么? 据我了解,实际上它将 _myEventnull 进行了比较,但我不确定。

最佳答案

如果您实现自定义添加/删除访问器,您将无法首先将 MyEvent 与 null 进行比较,因为它是一个事件 -它没有这样的值(value),只有添加/删除访问器。您将不得不使用您的声明字段(上面示例中的_myEvent)。

当您使用类似字段的事件时,您只能使用事件名称进行比较,在这种情况下您最终会(有效地)得到同名的字段和事件。 (编译后的代码不必实际重用字段名称的事件名称,但它必须看起来就像您编译时那样。)

注意使用这个:

if (MyEvent != null)
    MyEvent(this,EvtArgs.Empty);

不是线程安全的,因为 MyEvent 在检查和调用之间 可能变为 null。你应该使用:

EventHandler handler = MyEvent;
if (handler != null)
{
    handler(this, EventArgs.Empty);
}

另请注意,关于在 this 上锁定的类似字段的事件的部分现在有点过时了;在 C# 4 中,线程安全是使用无锁比较交换机制实现的。

关于c# - C#中事件的内部设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9976200/

相关文章:

c# - Knights Tour 递归 C# 我做这些事情的方式有问题

c# - 如何使用 C# 中的 MySQL 存储过程将表作为存储过程的输入发送?我有 T-SQL 工作

c# - 在 C# 中基于已知的 XSD 创建 Web 服务

c# - Android 上的 Xamarin.Forms "App has stopped working"

c# - 从 sqlDataReader 中获取一行的内容作为列表

c# - 哪个异步调用用于数据库连接和仍然响应的 GUI?--

c# - C# 中的引用类型

c# - 将小型 C# 校验和程序转换为 Java

c# - 结果与空 LINQ 查询的联合

c# - asp.net MVC自定义Authorize属性,传递参数和方法细节