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
或 false
- 我们确实知道
==
是 true
- 因为其中一个条件是
true
,另一个条件不可能不真实结果。这是逻辑or,不是and.
我的观点是 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。
我觉得这种行为不对。
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
或false
- 我们确实知道
==
是true
- 因为其中一个条件是
true
,另一个条件不可能不真实结果。这是逻辑or,不是and.
我的观点是 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 isbool
. 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。