为什么不能在Nullable <t> shorthands上调用静态方法?

时间:2017-05-31 12:57:56

标签: c# .net syntax-error nullable

我认为db.collection.update( {_id : ObjectId('592eae9a92e32cc41c1c9af7')}, { $set : { 'source.2.2': 'c' } } ); 只是T?的编译器简写。根据{{​​3}}:

  

语法Nullable<T>T?的简写,其中Nullable<T>是值类型。   这两种形式是可以互换的。

然而,有一点(微不足道)的差异:Visual Studio不允许我在短线上调用静态方法:

T

为什么呢?这种限制有什么理由吗?

2 个答案:

答案 0 :(得分:12)

您的MSDN引用回应了C#5.0规范的§4.1.10:

  

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

但“可互换”是过于简单化。确实T?表示System.Nullable<T>,但正如您所发现的那样,您无法在T?处使用System.Nullable<T>。特别是,示例中的成员访问(第7.6.4节)类型需要简单名称(第7.6.2节):

  

[§7.6]主要表达式包括最简单的表达形式。<​​/ p>      

基本表达式:
  初级无阵列创建表达式
  阵列创建表达式

     

初级无阵列创建表达式
  字面
  简单名称
  括号的表达式
  成员访问
  ...

     

[§7.6.2] 简单名称的格式为I或格式I<A1, ..., AK>,其中I是单个标识符<A1, ..., AK>是一个可选的 type-argument-list

     

[§7.6.4] 成员访问的格式为E.I或格式为E.I<A1, ..., AK>,其中E primary-expression I是单个标识符,<A1, ..., AK>是可选的 type-argument-list

Nullable<T>简单名称T?不是,所以前者编译而后者不编译。

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

事后看来,这是一个幸运的选择,它允许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<S> . Equals,调用类Equals的{​​{1}}静态方法?或者应该将其解析为Object,对变量S ?. Equals的{​​{1}}实例方法进行空条件调用?由于Equals不是简单名称,因此后者明确无误。

答案 1 :(得分:0)

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

您可以尝试使用您想要的任何值进行此单元测试:

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