【问题标题】:Nullable <= vs == comparison result可空 <= vs == 比较结果
【发布时间】:2015-07-30 11:02:28
【问题描述】:

我觉得这种行为是错误的。

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

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

  • &lt;= 表示 &lt;==
  • 我们不知道如何阅读&lt; - 它可能是truefalse
  • 我们知道==true
  • 因为其中一个条件是true,所以另一个条件不能不正确结果。这是逻辑,而不是

我的意思是 true or something else 应该是真的。

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

【问题讨论】:

  • 您是在问为什么语言是这样设计的,还是想要证明您所看到的行为符合该语言?
  • @JonSkeet 为什么语言是这样设计的 :) 我只是不明白为什么让它这样表现......
  • false 在这种情况下意味着“未知”。设计者本可以实现比较运算符(不包括 == 和 !=),以便它们返回可为空的布尔结果而不是布尔值,但使用它们的代码的可读性会受到明显影响。我猜他们更喜欢以这种方式实现它,尽管可能有明确记录的极端案例。
  • @vc74 请看编辑:)
  • @Randolphbirthdeath 返回 false,因为其中一个变量为空。 'birth = DateTime.Now' 的结果将是错误的

标签: c# comparison operator-keyword nullable


【解决方案1】:

根据 ECMA-334 标准(8.19 Nullable types)(强调我的):

当操作数类型既是非空值类型又是结果类型时,比较运算符(==!=&lt;&gt;&lt;=&gt;=)具有提升形式是 bool。比较运算符的提升形式是通过添加一个 ? 每个操作数类型的修饰符(但不是结果类型)。 == 的提升形式 和!= 运算符认为两个空值相等,一个空值不等于一个非空值。 &lt;&gt;&lt;=&gt;= 的提升形式 运算符如果一个或两个操作数为空,则返回 false

【讨论】:

    【解决方案2】:

    我理解您不是在寻找规范,而是为了解释为什么以这种方式设计可空对象。

    为了消除歧义,设计者可以让这些运算符返回 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类中已经存在的逻辑。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-29
      • 2012-04-26
      • 1970-01-01
      • 1970-01-01
      • 2019-09-12
      • 1970-01-01
      • 2011-05-30
      • 2019-05-18
      相关资源
      最近更新 更多