可为null<;=vs==比较结果

本文关键字:vs 结果 比较 null lt 可为 | 更新日期: 2023-09-27 18:05:44

我觉得这种行为不对。

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

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

编辑:

我知道以下比较返回false,因为无法说明它们之间的关系:

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

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

  • <=表示<==
  • 我们不知道如何读取<——它可能是truefalse
  • 我们知道==就是true
  • 由于其中一个条件是true,所以另一个条件不能不真实结果。这是逻辑,而不是

我的观点是true or something else应该为真。

我知道C#团队是这样设计的,但我的直觉不同。既然聪明人已经用这样的规则编写了C#,我只想了解为什么我的直觉在这里是错误的:(

可为null<;=vs==比较结果

根据ECMA-334标准(8.19可为空类型((emphasis mine(:

当操作数类型都是不可为null的值类型并且结果类型为时,比较运算符(==!=<><=>=(具有提升形式bool。比较运算符的提升形式是通过添加?修饰符用于每个操作数类型(但不用于结果类型(。==的提升形式和!=运算符认为两个null值相等,一个null值不等于一个非null值。<><=>=的提升形式如果一个或两个操作数都为null,则运算符返回false

我理解你不是在寻找规范,而是在解释为什么可以用这种方式设计null。

为了消除歧义,设计者可以让这些运算符返回bool?值,而不是在其中一个操作数为空的情况下为空的bool值。

但如果他们做出了这个选择,代码看起来会是:

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

这有点麻烦。

顺便说一句,看起来,在IL中,C#编译器首先生成与默认值的比较,然后检查其中一个操作数是否为空,这似乎有点奇怪。。。

.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类中已经存在的逻辑。