【问题标题】:Why is it impossible to call static methods on Nullable<T> shorthands?为什么不能在 Nullable<T> 简写上调用静态方法?
【发布时间】:2017-05-31 12:57:56
【问题描述】:

我认为T? 只是Nullable&lt;T&gt; 的编译器简写。根据MSDN

语法T?Nullable&lt;T&gt; 的简写,其中T 是一个值类型。 这两种形式可以互换。

但是,有一点(微不足道的)区别:Visual Studio 不允许我以速记方式调用静态方法:

bool b1 = Nullable<int>.Equals(1, 2); //no error
bool b2 = int?.Equals(1, 2); //syntax error "Invalid expression term 'int'"

为什么?这种限制有什么原因吗?

【问题讨论】:

  • 这是一个很好的问题,虽然我不知道那是什么意思,我们会尝试用 Nullable.Equals(1, 2) 测试什么? (我不是刻薄,这是一个真正的问题)
  • 从 C# 6 开始,?. 用作空条件检查,因此是语法错误。使用不能将?. 识别为单个运算符的早期版本时,情况可能会有所不同。
  • @TetsuyaYamamoto int 绝对不是表达式也不是变量,因此不能进行空条件检查。没有歧义。
  • 不。不限于 C#6 在 5 中也不起作用。
  • @HansPassant 语言规范明确提到“the two forms can be used interchangeably”。如果这确实是表达式解析器的限制,并且实际上并没有得到规范的支持,那么它就是编译器中的一个错误。

标签: c# .net syntax-error nullable


【解决方案1】:

您的 MSDN 引用与 C# 5.0 规范的 §4.1.10 相呼应:

可空类型写为T?,其中T 是基础类型。此语法是System.Nullable&lt;T&gt; 的简写,两种形式可以互换使用。

但“可互换”过于简单化了。确实T? 表示System.Nullable&lt;T&gt;,但正如您所发现的,您不能在任何可以使用System.Nullable&lt;T&gt; 的地方使用T?。特别是,您的示例中的那种 member-access (§7.6.4) 需要 simple-name (§7.6.2):

[§7.6] 主要表达包括最简单的表达形式。

主表达式:
primary-no-array-creation-expression
数组创建表达式

primary-no-array-creation-expression
字面意思
简单的名字
带括号的表达式
会员访问
...

[§7.6.2] simple-nameII&lt;A1, ..., AK&gt; 的形式,其中 I 是单个标识符,&lt;A1, ..., AK&gt; 是可选类型参数列表

[§7.6.4] member-accessE.IE.I&lt;A1, ..., AK&gt; 的形式,其中E 是一个主表达式 em>,I 是单个标识符,&lt;A1, ..., AK&gt; 是可选的type-argument-list

Nullable&lt;T&gt; 是一个 simple-nameT? 不是,所以前者编译而后者不编译。

为什么 C# 语言设计者需要 member-access 表达式来使用 simple-name 而不是任何 type?我想只有他们可以肯定地说,但也许这个要求简化了语法:在表达式中,编译器可以假设 ? 始终是条件(三元)运算符,而不是可能的可为空的类型说明符。

不过事后看来,这是一个幸运的选择,它允许 C# 6.0 添加 ?. 运算符而不会破坏现有程序。例如,考虑这个病态的例子:

struct S
{
    public bool Equals(int x, int y) { return false; }
}

class C
{
    public static void Main()
    {
        S? S = new S();
        Console.WriteLine(S?.Equals(1, 1)); // "True" or "False"?
    }
}

是否应该将S?.Equals 解析为Nullable&lt;S&gt; . Equals,调用Object 类的Equals 静态方法?还是应该将其解析为S ?. Equals,即对变量SEquals 实例方法的空条件调用?因为S? 不是一个简单名称,所以它无疑是后者。

【讨论】:

    【解决方案2】:

    虽然语法正确,但可以使用 Nullable 类型作为参数从默认类型调用 Equals 方法。

    你可以用你想要的任何值来尝试这个单元测试:

    int? i = 4;
    int? j = null;
    Assert.AreEqual(Nullable<int>.Equals(i, j), int.Equals(i, j));
    

    【讨论】:

    • 那是因为两个方法调用都只是调用object.Equals,它需要两个object 实例。这些都与object.Equals 相同。
    • 你是对的。我只是指出没有必要尝试调用'int?.Equals()'。
    猜你喜欢
    • 2011-03-02
    • 1970-01-01
    • 2016-12-23
    • 1970-01-01
    • 2012-07-02
    • 1970-01-01
    • 2018-09-20
    • 2014-01-03
    相关资源
    最近更新 更多