【问题标题】:Is this a bug in Visual Studio 2010 compiler?这是 Visual Studio 2010 编译器中的错误吗?
【发布时间】:2013-07-09 12:52:14
【问题描述】:
DateTime? date = null;
string tmp = "a" + "(" + date ?? "blablabla" + ")";

Console.WriteLine(tmp);

这将打印接近:'a ('

这是null-coalescing operator 的错误吗? 如果我将date ?? "blablabla" 放在括号中,则下划线为错误。

【问题讨论】:

  • 不要用大括号将date ?? "blablabla" 括起来,而是用括号括起来,如果这有什么改变,请告诉我们。
  • "这是编译器错误吗?" 99.99% 的答案是
  • 我只发现过一个编译器错误,那是 20 年前的事了。并且这一点很容易确认,因为调用在该特定编译器的一个版本中被编译为故障代码,但在先前和后续版本中的行为不同(并且正确)。这不是那样的情况。

标签: c# .net visual-studio-2010


【解决方案1】:

Null-coalescing operator ?? 的优先级低于+ 运算符,因此您的代码等于

string tmp = ("a" + "(" + date) ?? ("blablabla" + ")");

由于 + 操作中的所有字符串都会生成字符串(通过对所有非字符串操作数调用 .ToString()),因此您的代码将始终生成 "a(" 字符串。

【讨论】:

  • “优先级”优于“优先级”,我会说。
  • 还需要注意的是,与 null 连接的非 null 字符串会产生非 null 字符串,而不是错误或 null,因此 + date 实际上是一个空操作。
【解决方案2】:

首先,你应该always assume it's your fault,不是编译器的错; select isn't broken。您是否真的认为 ?? 运算符的 Visual Studio 2010 实现尚未经过实战测试?当您遇到与您的期望不符的事情时,请检查您的期望。拿出手册,确保理解准确会发生什么。在这种情况下,请打开语言规范。

如果您继续阅读specification 的第 1.4 节,您将看到一个将运算符分组为优先级分组的表格;你也可以找到它online。特别是,空合并运算符?? 位于底部 附近,仅高于低级条件三元运算符和赋值以及=>。它在下面加法运算符。因此,您的声明

string tmp = "a" + "(" + date ?? "blablabla" + ")";

被编译器视为

string tmp = (("a" + "(" + date) ?? ("blablabla" + ")"));

我不会完全迂腐,并且将第一个加法表达式1括起来。由于该语句中表达式的左侧从不为空,当然它总是分配"a("(或"a("+date.ToString()当@ 987654334@ 为真)到tmp

主要点是对应该发生的事情有一个错误的预期,应该根据手册进行验证。

如果我把date ?? "blablabla" 放在括号中,它会被下划线标记为错误。

当然是。您甚至阅读了错误消息吗?它可能会告诉您,您不能在DateTime?string 上执行??,因为DateTime?string 在任一方向上都没有隐式转换。这也包含在语言规范中;见第 7.13 节。您必须阅读此消息并回复。要获得 语义 等同于您要表达的内容尝试,您将不得不求助于条件三元运算符:

date.HasValue ? date.ToString() : "blablabla"

然后将整个内容用括号括起来,因为条件三元运算符的优先级非常很低。

最后,我发现您的代码的正确括号版本相当丑陋,阅读起来并不有趣,而且维护起来可能也不愉快。请简单点:

var tmp = String.Format("a({0})", 
                       date.HasValue ? date.ToString() : "blablabla");

现在所以清楚正在发生什么以及将要发生什么。我不必思考就能理解它。把你的想法留到你将遇到的困难问题上。

1:小心。在尝试正确确定首先评估的内容之前,我们需要添加对date.ToString(具有最高优先级)的方法调用。

【讨论】:

  • 这个答案比选的好很多。
【解决方案3】:

这里只是另一个版本:

DateTime? date = null;
string tmp = string.Format("a({0})", 
                           date.HasValue ? date.ToString() : "blablabla");

我真的很喜欢 string.Format 而不是串联。

【讨论】:

  • 我也是;除了最简单的表达式之外,我认为它会导致代码更具可读性和可维护性。
【解决方案4】:

"blablabla" 不是日期,所以不能使用 is 设置date?


string tmp = "a" + "(" + date ?? "blablabla" + ")";

等价于

string tmp = ("a" + "(" + date) ?? ("blablabla" + ")");

这是您的a( 的来源。


然而

string tmp = "a" + "(" + (date ?? DateTime.Now) + ")";

或类似的应该可以工作。

【讨论】:

    【解决方案5】:

    来自C# Language Specification §1.4

    下表总结了 C# 的运算符,列出了运算符 类别按优先级从高到低排列。中的运算符 同一类别具有相同的优先级。

    它说Additive operators 的优先级高于空合并运算符。

    因此,+ 的优先级高于 ??,这就是 "blablabla" + ")" 表达式首先起作用的原因。

    由于datenull,因此该语句的工作方式类似于;

    string tmp = "a" + "(" + null;
    

    通常结果是a(

    【讨论】:

      【解决方案6】:

      这很可能是因为date 不是字符串并且?? 运算符无法确定date"blablabla" 的通用基本类型。试试(date.ToString() ?? "blablabla")。但这也不能满足您的需求,因为date.ToString() 永远不会是null

      string tmp = "a" + "(" + (date ?? DateTime.Now) + ")";
      

      应该可以。

      【讨论】:

      • 另外,如果datenull,并且您尝试在其上调用ToString(),您将得到NullReferenceException(嗯,这可能只适用于可空类型是引用类型——而DateTime 是一个ValueType,所以它的可为空值将是值类型Nullable<T> 而不是基于类的——所以也许这样可以吗?)。
      • @fourpastmidnight 你的建议是正确的 - ((DateTime?)null).ToString() 执行没有错误。
      【解决方案7】:

      这不是空合并运算符的错误。

      我是operator precedence:

      "a" + "(" + date ?? "blablabla" + ")"
      

      等同于:

      ("a" + "(" + date.ToString() ) ?? ( "blablabla" + ")" )
      

      并且("a" + "(" + date.ToString() ) 不为空。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多