当==未定义时,为什么==运算符适用于Nullable <T>?

dev*_*xer 12 c# nullable operator-overloading operators

我只是看着这个答案,其中包含Nullable<T>.NET Reflector 的代码,我注意到两件事:

  1. Nullable<T>去往时需要显式转换T.
  2. ==运营商没有定义.

鉴于这两个事实,令我惊讶的是,这编译:

int? value = 10;
Assert.IsTrue(value == 10);
Run Code Online (Sandbox Code Playgroud)

与代码value == 10,无论是value被神奇转化为int(因此允许int==操作者使用,或==操作者被用于被奇迹般地定义Nullable<int>(或者,我假定的可能性较小,反射器是留出一些代码).

我希望必须做以下其中一项:

Assert.IsTrue((value.Equals(10)); // works because Equals *is* defined
Assert.IsTrue(value.Value == 10); // works because == is defined for int
Assert.IsTrue((int?)value == 10); // works because of the explicit conversion
Run Code Online (Sandbox Code Playgroud)

这些当然有效,但==也有效,而这是我没有得到的部分.

我之所以注意到这一点并且问我这个问题的原因是我正在尝试编写一个类似于它的结构Nullable<T>.我从上面链接的Reflector代码开始,并做了一些非常小的修改.不幸的是,我的CustomNullable<T>工作方式不同.我无法做到Assert.IsTrue(value == 10).我得到"运算符==不能应用于类型的操作数CustomNullable<int>int".

现在,无论修改多么微小,我都不希望能做到......

CustomNullable<T> value = null;
Run Code Online (Sandbox Code Playgroud)

......因为我明白,有一些编译落后魔术Nullable<T>允许值设置为null,即使Nullable<T>是一个结构,但我想到我应该能够模仿的所有其他行为Nullable<T>,如果我的代码被写入(几乎)相同.

任何人都可以了解当各种操作员Nullable<T>看起来没有被定义时的工作方式吗?

Eri*_*ert 29

鉴于这两个事实,令我惊讶的是,这编译

鉴于这两个事实,这是令人惊讶的.

这是第三个事实:在C#中,大多数运营商都被"提升为可空".

通过"提升为可空",我的意思是,如果你说:

int? x = 1;
int? y = 2;
int? z = x + y;
Run Code Online (Sandbox Code Playgroud)

那么你得到的语义是"如果x或y为null,则z为null.如果两者都不为null,则添加它们的值,转换为nullable,并将结果赋值给z."

平等也是如此,尽管平等有点奇怪,因为在C#中,平等仍然只是双值.要妥善解除,平等应该是三值:X ==Ÿ应该是,如果x或y是空的,真的还是假的,如果X和Y均为非空.这就是它在VB中的工作方式,但不适用于C#.

Nullable<T>如果我的代码编写(几乎)相同,我希望我能够模仿所有其他行为.

你将不得不学会失望,因为你的期望与现实完全不符.Nullable<T>是一种非常特殊的类型,它的神奇属性深深地嵌入在C#语言和运行时中.例如:

  • C#自动将运营商提升为可空.没有办法说"自动将操作员提升到MyNullable".您可以通过编写自己的用户定义的运算符来获得相当接近.

  • C#具有空文字的特殊规则 - 您可以将它们分配给可空变量,并将它们与可空值进行比较,编译器会为它们生成特殊代码.

  • nullables的拳击语义非常奇怪,并且融入运行时.没有办法模仿它们.

  • 对于可空语义is,as并凝聚运营商都在烘焙的语言.

  • Nullables不满足struct约束.没有办法效仿.

  • 等等.