我已经编了一段时间了,只是发现了一些有趣的东西。所以通常当我在一个类中实现事件时,我想在尝试调用它之前检查事件的null状态,所以我使用以下语法:
private void OnEvent(EventArgs e)
{
if (Event != null) Event(this, e);
}
但我今天在Visual Studio中发现了一些内容,它是代码简化建议,它建议将以下语法简化为:
private void OnEvent(EventArgs e)
{
Event?.Invoke(this, e);
}
是否有人熟悉这个“?”句法?它是检查任何事物或仅代表的空状态的通用速记吗?它不是Linq框架的一部分,它是一种内置语法。任何洞察这个以及它的用途都会有所帮助。我没有太多的搜索,但没有具体找到任何东西。
答案 0 :(得分:6)
我在上面留下了一些评论,但我觉得它们非常重要,可以被称为答案。
首先,正如其他人所说,这是空条件运算符。
此版本的代码被认为是糟糕的样式,因为在检查后事件可能会变为null,如果在另一个线程上修改:
private void OnEvent(EventArgs e)
{
if (Event != null) Event(this, e);
}
但是,我注意到在任意线程上调用,订阅和取消订阅事件的多线程程序相对较少。
添加null条件运算符之前的标准建议是编写笨拙的:
private void OnEvent(EventArgs e)
{
var ev = Event;
if (ev != null) ev(this, e);
}
如果有比赛,这将消除空取消引用。
null条件运算符是相同的:
private void OnEvent(EventArgs e)
{
Event?.Invoke(this, e);
}
这只是var ev = Event; if (ev != null) ev.Invoke(this, e);
的缩写。
现在,人们会告诉你后两个版本,无论是使用本地版本,还是更简洁,使用?.
,都是"线程安全"。 他们不是。这些不会取消引用null,但这不是有趣的种族。有趣的比赛是:
Thread Alpha: create disposable object X -- say, a log file writer
Thread Alpha: subscribe X.H to event
Thread Bravo: Cause event to fire
Thread Bravo: Save X.H into local and check for null. It's not null.
Thread Alpha: Unsubscribe X.H from event
Thread Alpha: Call Dispose on X -- the log file is now closed.
Thread Bravo: Invoke X.H via the local
现在我们已经调用了一个被处置对象的方法,如果对象被正确实现,它应该抛出一个"对象。例外。如果没有,嘿,它会尝试写入一个已关闭的文件,一切都会破坏,是的!
在多线程环境中,事件处理程序必需可以安全地调用永远,甚至 之后取消订阅事件。没有任何"线程安全"在呼叫网站上将解决这个问题;这是处理程序的要求。但处理程序的作者如何知道它们将在多线程环境中使用,并相应地进行规划?通常,他们不会。事情就这样发生了。
如果您不喜欢,那么不要编写在多个线程上使用事件的程序。很难做到正确,每个人 - 来源和处理程序 - 必须合作以确保它有效。
现在,有些人可能会说,解决方案是不是锁定处理程序?
private object HandleLocker = new object();
...
private void OnEvent(EventArgs e)
{
lock (HandleLocker)
{
if (Event != null)
Event(this, e);
}
}
然后同样为add
的{{1}}和remove
添加锁定。
这是一种比疾病更糟糕的治疗方法。
Event
现在我们有两个线程,每个线程都在等待另一个完成。在Charlie释放HandleLocker之前,Bravo无法移动,而且在Bravo释放Foo之前Charlie无法移动。
永远不要这样做。再次:如果您处于多线程事件处理程序中,则需要确保在陈旧时调用处理程序,并且您可能不会使用锁来执行此操作。这是一个糟糕的情况;锁是管理线程的标准机制。
多线程很难。如果你不了解事情可能出错的所有方式,以及如何避免它们,就不要编写多线程程序。
答案 1 :(得分:0)
?
/'null条件运算符'只是在执行成员访问或索引操作之前测试null的简便方法。
您可以在这里阅读更多内容: https://msdn.microsoft.com/en-us/library/dn986595.aspx
答案 2 :(得分:0)
这称为Null-Conditional运算符,在许多情况下都很有用。它和Null-Coalescing运算符(??)是非常干净,富有表现力的方法,可以在取消引用某些内容或提供干净的默认值之前检查null。
了解更多信息 https://msdn.microsoft.com/en-CA/library/dn986595.aspx