为什么没有C#编译器抛出null的逻辑比较?

时间:2018-04-03 18:04:13

标签: c# logic

我昨天和朋友一起吃午饭,他们在C#中抱怨null。他说null是不合逻辑的。我决定测试他的说法,所以我测试了一些简单的逻辑命题:

Console.WriteLine(null == null); //True
//Console.WriteLine(null == !!null); //BOOM

Console.WriteLine(10 >= null); //False
Console.WriteLine(10 <= null); //False

Console.WriteLine(!(10 >= null)); //True
Console.WriteLine(!(10 <= null)); //True

检查平等似乎很简单,这就是我所期望的。然而,更多/更少的陈述是逻辑矛盾,我觉得这真的很混乱!不应该抛出这些吗?否定操作会像你期望的那样抛出。

如果我尝试在Ruby或Python中使用null运行比较(除了相等),我会得到一个类型错误,而不是#34;无法将数字与nil&#34;进行比较。为什么C#不这样做?

5 个答案:

答案 0 :(得分:13)

很棒的问题。

尽量不要将null视为特定值,而是#34;这里没什么可看的。&#34; documentationnull定义为

  

null关键字是表示空引用的文字,不引用任何对象。

考虑到这一点,null不是一个对象的事实意味着经典的思想规律并不完全适用于它(或者,至少,不适用于它)与它适用于实际对象的方式相同。)

话虽如此,10 >= null10 <= null都是false的事实并非严格来说,这是一个矛盾 - 毕竟,null是相当的几乎没有。如果你说10 >= (some actual thing)10 <= (some actual thing)都是假的,那么显然这是矛盾的,但如果没有一些实际的对象,你就不可能在经典意义上产生矛盾。亚里士多德对形而上学的定律如下:

  

同一个东西不可能同时归属于属于同一个对象并且在同一方面,以及可能产生的所有其他规范,让它们被添加满足当地的反对意见......

所以,我们有一点&#34;漏洞&#34;从某种意义上说。至少亚里士多德制定了“不矛盾法”,它特指的是对象。当然,在这一点上,对“非矛盾法”有多种解释。

现在,转向10 + null的情况。如果它更容易,我们可以说这与null + 10相同。从某种意义上说,在这一点上应该发生什么 - 应该null&#34;吞噬&#34; 10,或者我们应该说&#34; 10 +(什么都没有)真的应该等于10&#34;?说实话,从逻辑的角度来看,我没有一个非常有说服力的答案,除了说&#34;嗯,这是一种设计选择。&#34;我怀疑语言设计师想要将10 + null10 + 0区分开来,但我没有文件来证明这一点。 (实际上,如果它们是相同的话会有点奇怪;毕竟,0是一个可以从自然数构造的实际值,但是null是&#34;没有任何值&#34;)。

答案 1 :(得分:10)

  

我知道它在某个地方的语言规范中,并不是我有兴趣知道的。我有兴趣理解为什么这些逻辑违规似乎存在,或者我对逻辑规律的理解是不正确的。

编程语言不应该遵循哲学隐含的逻辑规则,无论如何,编程语言意味着解决具体的行业/业务相关问题。许多语言甚至不遵守数学思维规则,如代数表达式,范畴理论等等,所以...

  

10必须大于或小于null ...不应该吗?

不,&#34; null关键字是表示空引用的文字,一个不引用任何对象&#34;,并且根据C#规则,编译器扫描提供的可用运算符如果其中一个参与者是null,则表达式的结果为null

寻找lifted operators

  

10 + null如何才能为null?

见上文。

答案 2 :(得分:4)

如果你不认为'null'是一个值,它会有所帮助 - 这是一个虚无或缺乏价值的概念。它不只是C# - 你会在SQL中遇到同样的事情(NULL +'asdf'会导致NULL。)

所以像(NULL&lt; 10)这样的东西本身并没有最合乎逻辑的意义 - 你将虚无的概念与实际的数字进行比较。从技术上讲,不,虚无不小于10.它也不超过10。这就是为什么它在两种情况下都返回false。

你被警告远离NULL的原因与逻辑无关。  这里有一个很好的例子,说明为什么NULL中的C#经常会导致错误/错误:

private NumericalAnalysis AnalyzeNumber(int someValue)
{
    if (someCondition)
        return null;
    return new NumericalAnalysis(someValue);
}

...好吧,现在我们可以调用AnalyzeNumber()并开始使用NumericalAnalysis:

NumericalAnalysis instance = AnalyzeNumber(3);
if (instance.IsPrime)
    DoSomething();

...哎呀!你刚碰到一个bug。您调用了AnalyzeNumber(),但在使用它之前没有检查返回值是否为null。毕竟,AnalyzeNumber()有时会返回一个空值 - 所以当调用instance.IsPrime时,它会爆炸。你必须在每次调用该函数的时候“if(myVar == null)”检查 - 如果你忘了,你刚刚介绍了一个错误。

答案 3 :(得分:2)

我不是C#语言设计师,所以(耸耸肩),但就个人而言,我认为它是原始类型的系统故障,所以我的脑袋可以按原样接受它。

原因在于,逻辑上,您不能将确定性值(例如int)与不确定值(可为空的int)进行比较,而无需进行某种转换。它们实际上是两种不同的类型,但现代编程语言只是试图以自己的方式将它们涂抹在一起。

我也认为null是一个好的和有用的东西,因为我们从来没有完整的数据,也从不想要完整的数据,因为我们只需要它的一部分用于手头的活动。

答案 4 :(得分:1)

我认为这是出于历史原因。在该语言的2.0版本中向C#添加可空值类型的主要动机是减轻在ADO.NET中使用可空的sql列的痛苦。因此,添加可空数字的设计与sql一样,等等。