为什么不能在 Nullable<T> 简写上调用静态方法?

Why is it impossible to call static methods on Nullable<T> shorthands?

我以为 T? 只是 Nullable<T> 的编译器 shorthand。根据MSDN:

The syntax T? is shorthand for Nullable<T>, where T is a value type. The two forms are interchangeable.

但是,有一点(微不足道的)区别:Visual Studio 不允许我在 shorthand 上调用静态方法:

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

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

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

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

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

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

A nullable type is written T?, where T is the underlying type. This syntax is shorthand for System.Nullable<T>, and the two forms can be used interchangeably.

但是“可互换”过于简单化了。 T? 确实意味着 System.Nullable<T>,但正如您所发现的,您不能在可以使用 System.Nullable<T> 的所有地方使用 T?。特别是,您示例中的 member-access(§7.6.4)类型需要 simple-name(§7.6.2):

[§7.6] Primary expressions include the simplest forms of expressions.

primary-expression:
  primary-no-array-creation-expression
  array-creation-expression

primary-no-array-creation-expression
  literal
  simple-name
  parenthesized-expression
  member-access
  ...

[§7.6.2] A simple-name is either of the form I or of the form I<A1, ..., AK>, where I is a single identifier and <A1, ..., AK> is an optional type-argument-list.

[§7.6.4] A member-access is either of the form E.I or of the form E.I<A1, ..., AK>, where E is a primary-expression, I is a single identifier and <A1, ..., AK> is an optional type-argument-list.

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

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

但事后看来,这是一个幸运的选择,它允许 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,调用classObjectEquals静态方法?还是应该解析为S ?. Equals,对变量SEquals实例方法的空条件调用?因为 S? 不是 单名 ,所以毫无疑问是后者。