Nullable <= vs == 比较结果

Nullable <= vs == comparison result

我觉得这种行为不对。

DateTime? birth = null;
DateTime? death = null;

Console.WriteLine(birth == death); // true
Console.WriteLine(birth <= death); // false

为什么会这样?这太奇怪了。当然,我的意思是为什么第二个表达式的计算结果也不是 true

编辑:

我理解以下比较 return false,因为无法说明它们之间的关系:

Console.WriteLine(birth < death); // false
Console.WriteLine(birth > death); // false

这是完全可以理解的行为。但是……看看逻辑:

我的观点是 true or something else 应该是正确的。

我知道 C# 团队是这样设计的,但我的直觉不同。既然聪明人用这样的规则写了C#,我就想学学为什么我的直觉在这里错了:)

根据 ECMA-334 标准(8.19 可空类型)(强调我的):

A comparison operator (==, !=, <, >, <=, >=) has a lifted form when the operand types are both non-nullable value types and the result type is bool. The lifted form of a comparison operator is formed by adding a ? modifier to each operand type (but not to the result type). Lifted forms of the == and != operators consider two null values equal, and a null value unequal to a non-null value. Lifted forms of the <, >, <=, and >= operators return false if one or both operands are null.

我知道您不是在寻找规范,而是在寻找为什么可以这样设计可为 null 的解释。

为了消除歧义,设计者可以让这些运算符 return 一个 bool? 值而不是 bool 值,如果其中一个操作数为空,则该值将为空.

但如果他们做出了这个选择,代码将如下所示:

bool? comparison = birth <= death; 
if (comparison.HasValue && comparison.Value)
{
}

有点麻烦

附带说明一下,从 IL 来看,C# 编译器似乎首先生成与默认值的比较,然后检查其中一个操作数是否为 null,这看起来有点奇怪...

.method private hidebysig static void  Main(string[] args) cil managed
{
  .locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> x,
           [1] valuetype [mscorlib]System.Nullable`1<int32> V_1,
           [2] valuetype [mscorlib]System.Nullable`1<int32> V_2)
  IL_0000:  ldloca.s   x
  IL_0002:  ldc.i4.1
  IL_0003:  call       instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
  IL_0008:  ldc.i4.2
  IL_0009:  newobj     instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
  IL_000e:  ldloc.0
  IL_000f:  stloc.1
  IL_0010:  stloc.2
  IL_0011:  ldloca.s   V_1
  IL_0013:  call       instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
  IL_0018:  ldloca.s   V_2
  IL_001a:  call       instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
  IL_001f:  ble.s      IL_0024
  IL_0021:  ldc.i4.0
  IL_0022:  br.s       IL_0033
  IL_0024:  ldloca.s   V_1
  IL_0026:  call       instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
  IL_002b:  ldloca.s   V_2
  IL_002d:  call       instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
  IL_0032:  and
  IL_0033:  brfalse.s  IL_003a
  IL_0035:  call       void [mscorlib]System.Console::WriteLine()
  IL_003a:  ret
} // end of method Program::Main

它也是复制静态中已经存在的逻辑Nullable class。