【问题标题】:Math operations with null带有 null 的数学运算
【发布时间】:2019-10-08 16:06:19
【问题描述】:

请解释为什么这个测试通过了?

[Test]
public void TestNullOps()
{
    Assert.That(10 / null, Is.Null);
    Assert.That(10 * null, Is.Null);
    Assert.That(10 + null, Is.Null);
    Assert.That(10 - null, Is.Null);
    Assert.That(10 % null, Is.Null);
    Assert.That(null / 10, Is.Null);
    Assert.That(null * 10, Is.Null);
    Assert.That(null + 10, Is.Null);
    Assert.That(null - 10, Is.Null);
    Assert.That(null % 10, Is.Null);

    int zero = 0;
    Assert.That(null / zero, Is.Null);
}

我什至不明白这段代码是如何编译的。

看起来每个带有 null 的数学表达式都返回 Nullable<T>(例如,10 / nullNullable<int>)。但我在Nullable<T> 类中看不到运算符方法。如果这些运算符取自int,为什么最后一个断言没有失败?

【问题讨论】:

    标签: c#


    【解决方案1】:

    来自MSDN

    为值类型存在的预定义一元和二元运算符以及任何用户定义的运算符也可以由可空类型使用。如果操作数为空,则这些运算符产生空值;否则,运算符使用包含的值来计算结果。

    这就是为什么所有的测试都通过了,包括最后一个——不管操作数的值是什么,如果另一个操作数是null,那么结果就是null

    【讨论】:

    • 注意==这里的规则略有不同;如果 both 为 null,则为 true
    • 是的,据我所知!= 也是如此 - 如果一个为空,另一个不是,则结果为 true
    • 另外说明,比较运算符(<><=>=)不返回可空值;如果其中一个或两个操作数为空,它们只会返回 false。
    【解决方案2】:

    Nullable<T> 的运算符是所谓的“提升”运算符]; c# 编译器采用可用于T 的运算符并应用一组预定义规则;例如,对于+,如果任一操作数为空,则提升的+null,否则为内部值的总和。最后一个;同样,如果任一操作数是 null,则除法定义为 null - 它永远不会执行除法。

    【讨论】:

    • 编译器会不会只是把它翻译成别的东西?看我的回答。
    • @MarcGravell 如果从不执行除法,为什么编译器不编译Assert.That(null / 0, Is.Null);
    • @altso - 我很困惑;您说“为什么最后一个断言没有失败”-实际上,它没有失败(AFAIK)-null/0null...?
    • @MarcGravell 帖子中的断言与我的评论之间存在差异。在注释中,零是一个常数。并且编译器失败了。
    【解决方案3】:

    我尝试使用反射器从下面的代码中查看生成的代码

    var myValue = 10 / null;
    

    编译器把它变成这样:

    int? myValue = null;
    

    而且这不会编译,所以你不能欺骗它:

    object myNull = null;
    var myValue = 10 / myNull;
    

    【讨论】:

    • 是的,但这只是重申了这个问题,因为在这两种情况下都是编译器这样做(使用相同的规则)——简单地说,它恰好能够做到在这种情况下,它是一个常数值。
    【解决方案4】:

    我假设编译器将zero 转换为Nullable<int>,并提供底层除法运算符。由于Nullable 类型可能为null,因此在编译期间不会捕获除以0。最好的猜测是,他们希望您能够在出现 div/0 的情况下进行空测试。

    【讨论】:

      【解决方案5】:

      此列表中的操作始终返回 NULL:

      1 + 2 + 3 + NULL
      
      5 * NULL - 7
      
      'Home ' || 'sweet ' || NULL
      
      MyField = NULL
      
      MyField <> NULL
      
      NULL = NULL
      

      【讨论】:

      • 请注意,不鼓励仅链接的答案(链接会随着时间的推移变得陈旧)。请考虑在此处编辑您的答案并添加概要。
      • 这在我看来不像 C#。这是什么语言?
      • 那是一般@sam
      • 这是一个无关紧要的答案——它是关于 SQL,而不是 C#。 (并且您应该保留link 作为答案的一部分 - 可以看出该链接是关于 Firebird SQL 服务器的。)
      猜你喜欢
      • 2018-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-08
      • 1970-01-01
      • 2019-08-25
      • 2013-02-16
      • 2014-03-08
      相关资源
      最近更新 更多