快速C#语法说明

时间:2017-03-27 20:29:37

标签: c# syntax

我已经编了一段时间了,只是发现了一些有趣的东西。所以通常当我在一个类中实现事件时,我想在尝试调用它之前检查事件的null状态,所以我使用以下语法:

private void OnEvent(EventArgs e)
{
   if (Event != null) Event(this, e);
}

但我今天在Visual Studio中发现了一些内容,它是代码简化建议,它建议将以下语法简化为:

private void OnEvent(EventArgs e)
{
   Event?.Invoke(this, e);
}

是否有人熟悉这个“?”句法?它是检查任何事物或仅代表的空状态的通用速记吗?它不是Linq框架的一部分,它是一种内置语法。任何洞察这个以及它的用途都会有所帮助。我没有太多的搜索,但没有具体找到任何东西。

3 个答案:

答案 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