c# - 如果我将对事件对象的引用复制到另一个对象并随后更改事件对象会怎样?

标签 c# .net events delegates clr

我正在读一本关于 C# 和 CLR 的书,但有一点无法理解。正文如下:

To fix this race condition, many developers write the OnNewMail method as follows:

// Version 2
protected virtual void OnNewMail(NewMailEventArgs e) {
    EventHandler<NewMailEventArgs> temp = NewMail;
    if (temp != null) temp(this, e);
}

The thinking here is that a reference to NewMail is copied into a temporary variable, temp, which refers to the chain of delegates at the moment the assignment is performed. Now, this method compares temp and null and invokes temp, so it doesn’t matter if another thread changes NewMail after the assignment to temp. Remember that delegates are immutable and this is why this technique works in theory.

所以,问题是:为什么它会起作用?我认为 temp 和 NewMail 对象引用同一个对象,无论必须更改哪个对象 - 结果都会影响两者。谢谢!

最佳答案

CLR 和 MulticastDelegate 中的委托(delegate)类型特别是 type,尽管它们是引用类型,但属于称为“不可变”类型的罕见类型组。这意味着此类类型的引用分配操作会创建实例的副本,这与仅复制引用值的常规引用类型的分配不同。所以当你写:

EventHandler<NewMailEventArgs> temp = NewMail;

NewMail 引用的委托(delegate)的新副本创建并将对此副本的引用分配给 temp变量,因此执行此行后将有 EventHandler<NewMailEventArgs> 的两个实例delegate: NewMail 引用的实例以及 temp 引用的另一个实例(不是像您想象的那样由两个变量引用的单个实例)。这就是为什么现在您可以安全地调用 temp 指向的委托(delegate)。因为在调用委托(delegate)的一段时间内它不能被另一个线程置空。

关于c# - 如果我将对事件对象的引用复制到另一个对象并随后更改事件对象会怎样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55322255/

相关文章:

c# - 'Disabled ghost property fetching for <entity> because it does not support lazy at the entity level'的含义

c# - 将常规类库转换为 ASP.NET 5 (vnext)

java - 在 Java 中通过 Bouncy CaSTLe 验证 pkcs7 SignedData

.net - 为什么 "vcredist_x86_2010_sp1.exe,Asia"不允许我安装 SQLite?

javascript - jQuery 事件命名空间可以包含破折号吗?

c# - 如何检测 WebBrowser 控件中的复选框何时被选中?

c# - 从 C# 调用 C++ 时如何最好地处理未使用的指针?

c# - 如何在Windows窗体上有效地多线程?

c# - 如何使用 dotnet 在命令行中传递参数?

c# - 编译器警告 CS0067 : The event is never used