25

我偶然发现了一个有趣的站点,其中解决了 C# 6.0 的一些新(提议的)特性。您可以在此处阅读:Probable C# 6.0 features

我发现特别有趣的是一元空值检查(也称为空值传播运算符?.)。根据该网站,以下声明

var bestValue = points?.FirstOrDefault()?.X ?? -1;

包含 monadic null 检查,目前使用以下代码实现:

if (points != null) 
{
  var next = points.FirstOrDefault();
  if (next != null && next.X != null) return next.X;
}   
return -1;

我的第一眼是,嘿,这里到底写了什么?但是在查看“旧”代码之后,我开始喜欢它。

但是,我也开始收到一些问题,我想问一下。

  • 我假设这个空传播运算符是线程安全的。但这实际上是如何执行的?竞争条件会被删除还是会持续存在?
  • 该运算符将如何处理泛型类型?此外,它将如何处理不受约束的泛型类型?例如,考虑

    var resultAfterNullCheck = x?.Y;
    

    如果这里的类型 Y 是用引用类型、不可为空的值类型和可空的值类型来实例化的,那么就没有什么合理的可做(因为我想不出该怎么做,因为我根本不知道该怎么做)。那么是否会返回默认值?还是会抛出错误?

  • 在查看该站点提供的示例(以及我在上面复制的示例)时,我假设空传播运算符的主要好处之一是它只会评估该语句一次。但是(可能是由于我对 CLR 缺乏了解),我很好奇它是如何执行的。
    对我来说,第一次评估(如果 points 等于 null)应该触发扩展方法 FirstOrDefault() 以在 points 不为 null 时触发,然后将返回的类型评估为 null 与否,如果不是,X 将是回来。所以这些实际上是三个评价合二为一?还是我理解错误?这会影响执行速度吗?

换句话说,执行空值检查的旧方法或这个新的可爱运算符会更快吗?一旦 Visual Studio 2015 的下载完成,我将尝试通过执行一些研究来检查这一点……但这需要一点耐心……

对这种新的运算符类型有什么想法吗?它真的仍然是一个提议的,还是我们真的可以期望使用这个新的一元空值检查?

编辑
由于 Matthew Watson 提供了一篇很好的MSDN 文章来讨论这个(以及更多)主题,我很好奇它是否提到了我之前关于无约束泛型的问题以及这个运算符如何处理这个问题。不幸的是,我还没有找到答案。虽然我认为程序员应该尽量避免使用不受约束的泛型,但我仍然可以想象这有时是不可行的。如果是这样的话,是否真的需要重新设计?

4

3 回答 3

16

你想太多了。一个一个,你的问题:

  1. 你为什么认为它是线程安全的?调用成员函数不是。这只不过是调用具有空值预检查的成员函数,因此您只能获得与原始函数保证一样多的线程安全性。

  2. 如果您的泛型类型允许 null 比较(这是此运算符将在幕后使用的),则将发出代码。如果不是,您将收到编译错误(例如,如果您要求类型为值类型)。这涵盖了所有情况!

  3. 它被调用一次——每个运算符,就像普通.运算符一样。如果你说它A.b.c仍然是两级间接,并且使用这个 new 运算符没有什么不同,它也只是检查空值。

真正的好处?.是它的语义(你可以一眼看出你的代码试图做什么)和短路(使代码比嵌套if的 s 短很多)。您不会将.旧代码中的every 替换为?.,实际上您可能很少使用它。但是在某些情况下它会很有用,例如在 Linq 表达式中跟随...OrDefault()操作或调用事件。

于 2015-01-13T13:41:01.753 回答
8

为了部分回答您的第一个问题,根据John Skeet 在他的博客上的说法,空条件运算符?.(=空传播运算符)是线程安全的。

于 2015-07-14T09:41:09.920 回答
1

您可以在 Roslyn 项目讨论中找到有关计划功能的所有信息。您还可以使用 Roslyn 之类的 nuget-package 尝试使用控制台应用程序的新功能(这意味着它适用于 Visual Studio 2013 <)

于 2015-01-23T18:18:12.863 回答