这种行为听起来对我不对。
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
这是完全可以理解的行为。但是......看看逻辑:
<=
表示<
或==
<
- 可能是true
或false
==
是true
true
,其他条件不能不符合结果。这是逻辑或,而不是和。我的观点是 true or something else
应该是真的。
我知道C#团队就是这样设计的,但我的直觉却与众不同。既然聪明的人已经用这样的规则写了C#,我只想学习 为什么 我的直觉在这里是错误的:)
答案 0 :(得分:4)
根据ECMA-334标准( 8.19 Nullable types )(强调我的):
比较运算符(
==
,!=
,<
,>
,<=
,>=
)在操作数时具有提升形式types是非可空值的类型,结果类型是bool
。通过添加a形成比较运算符的提升形式 每个操作数类型的?
修饰符(但不是结果类型)。提升==
的形式 和!=
运算符认为两个空值相等,并且空值不等于非空值。提升<
,>
,<=
和>=
的形式 如果一个或两个操作数为空,则运算符返回false。
答案 1 :(得分:1)
我理解你不是在寻找规格,而是为了解释为什么以这种方式设计nullables。
为消除歧义,设计人员可以让这些运算符返回bool?
值而不是bool
值,如果其中一个操作数为空,则该值为null。
但是如果他们做出了这个选择,那么代码就像:
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类中已存在的逻辑。