为什么当==返回null时,> =返回false?


78

我有两个类型为int的变量?(或者,如果可以,则为Nullable <int>)。我想对两个变量进行大于或等于(> =)比较,但事实证明,如果两个变量均为null,则返回false,而显然==运算符返回true。

有人可以向我解释为什么这很逻辑,因为> =运算符的语义定义包含单词“或”吗?


1
您可以发布产生这种奇怪行为的代码吗?
Android前夕

12
实际上,我会质疑==返回true是否合适。我认为那根本不合适。如何将两个未知值的变量证明为相等?
查尔斯·布雷塔纳

2
@Charles,因为如果它们具有相同的空类型(例如int?),则它们的值已知的。 null
Moo-Juice 2010年

3
@ moo-juice,不在我的世界里...如果您的名字为空,您会回答吗?null与“ null”不同。有一部老电影叫“我的名字叫没人”(“谁摔碎了玻璃,孩子们?” ----“没人叫”)那谁是“没人”?在现实世界中(在代码内部),null表示该值未知...。数据结构值可能是已知的(它是Null),但是该变量所代表的实际问题域实体/值是不知道..
查尔斯·布雷塔纳2010年

2
@查尔斯,喜欢这个比喻!但是谁没有打破玻璃呢?
Moo-Juice 2010年

Answers:


97

当该功能最初是在C#2.0中设计的时,关于这种古怪性存在着巨大的争论。问题在于,C#用户已经完全习惯了这一点:

if(someReference == null)

将相等性扩展为可为空的值类型时,您可以选择以下内容。

  1. 真正的平等是可以消除的。如果一个或两个操作数为null,则结果既不是true,也不是false,而是null。在这种情况下,您可以:

    • a)在if语句中具有可为空的值类型相等是非法的,因为该if语句需要布尔值,而不是可为空的布尔值。相反,HasValue如果每个人都想比较为null ,则要求所有人使用。这是冗长和令人讨厌的。

    • b)自动将null转换为false。这样做的缺点是,x==null如果x为null,则返回false,这会造成混淆,并且不利于人们对引用类型的null比较的理解。

  2. 可提升的平等不会解除。可为空的相等性为true或false,与null的比较为null检查。这使得可为空的相等性与可为空的不等式不一致。

这些选择显然都不正确。他们都有优点和缺点。例如,VBScript选择1b。经过大量辩论,C#设计团队选择了第二名。


在选择#2中,可为空的相等如何与可为空的不平等不一致?
MCS 2010年

3
@MCS:正是从根本上激发问题的方式。当<=为假时,==可以为真。
埃里克·利珀特

@Eric:谢谢-我认为“不平等”仅指!=,实际上与==一致。没意识到这是一个数学术语:en.wikipedia.org/wiki/Inequality_( mathematics
MCS 2010年

1
好了,其他问题(你还没有解决)是当你尝试做的事<<==>,或者>当一个操作数为null。在C#中,答案是return false。在Scala / JavaString类中,答案是抛出NullPointerException
肯·布鲁姆

3
@Brian:那为什么要完全允许可空类型的运算符?如果它们总是抛出可为null的类型的null值,那么您最好只对非可为null的类型定义运算符,并使用户将转换插入为不可为null的类型,因为这是他们必须要做的尽力消除例外。
埃里克·利珀特

59

因为平等是与可比性分开定义的。
您可以测试,x == nullx > null毫无意义。在C#中,它将始终为false。


1
+1:这是MSDN链接msdn.microsoft.com/en-us/library/2cf62fcy.aspx,但是不幸的是,他们忘记了解释在出现2个null的情况下比较运算符的行为(他们只提到了相等性)...
digEmAll

3
是,但是运算符大于等于。我看到了真值表,但我倾向于同意OP,> =大于等于,如果null == null为true,null> = null也应为true。我想我们只是将其归结为实现和用户方便,以保留== null检查。
BlackICE 2010年

2
@David,请参阅Eric的回答,“这些选择显然都不正确”。但是总的来说,当一个类型是Equatable而不是Comparable时,就>=根本没有定义。
Henk Holterman

11

描述'> ='的另一种方式是:不小于。没有提及平等。一旦非相等测试中的操作数之一为Null,结果也将是未知的(为null)。但是,如果您想知道两个操作数是否均为Null,则Null == Null是一个合理的测试(应为true)。摆脱运营商的不平等部分,一切都是不同的。

来自http://msdn.microsoft.com/zh-cn/library/2cf62fcy.aspx#sectionToggle4的以下代码示例总结了C#如何处理Null:

int? num1 = 10;   
int? num2 = null;   
if (num1 >= num2)   
{   
    Console.WriteLine("num1 is greater than or equal to num2");   
}   
else   
{   
    // This clause is selected, but num1 is not less than num2.   
    Console.WriteLine("num1 >= num2 returned false (but num1 < num2 also is false)");   
}   

if (num1 < num2)   
{   
    Console.WriteLine("num1 is less than num2");   
}   
else   
{   
    // The else clause is selected again, but num1 is not greater than   
    // or equal to num2.   
    Console.WriteLine("num1 < num2 returned false (but num1 >= num2 also is false)");   
}   

if (num1 != num2)   
{   
    // This comparison is true, num1 and num2 are not equal.   
    Console.WriteLine("Finally, num1 != num2 returns true!");   
}   

// Change the value of num1, so that both num1 and num2 are null.   
num1 = null;   
if (num1 == num2)   
{   
    // The equality comparison returns true when both operands are null.   
    Console.WriteLine("num1 == num2 returns true when the value of each is null");   
}   

/* Output:   
 * num1 >= num2 returned false (but num1 < num2 also is false)   
 * num1 < num2 returned false (but num1 >= num2 also is false)   
 * Finally, num1 != num2 returns true!   
 * num1 == num2 returns true when the value of each is null   
 */   

这是一个有趣的心理模型。但是,C#规范的第1.4节称这些运算符小于或等于且大于或等于
Conrad Frix 2010年

3
@Conrad仅说明了将编程语言(在这种情况下为C#)翻译成英语的问题。恕我直言,每当Nulls进入逻辑时,您都需要处理三态结果(对,错,未知)。任何涉及Null的表达式都将导致未知,唯一的例外Null == x是对未知的显式测试,结果为true或false。
NealB 2010年

@NealB:实际上,规范指出> =和<=意味着您期望它们表示的含义-第7.10节明确指出,<=和> =的运算符'x op y'等于-到大于/小于,正如人们所期望的那样。
nicodemus13 2013年

2

>=对数值进行运算;哪个不是。

您可以使运算符超载>=以提供所需的特定类型的内容。


它确实对null类型进行操作,它返回false
BlackICE 2010年

它处理null类型,是……关于我们将定义为“操作”的语义。防御性编码;它是否为null,然后在评估过程中进行决策时将x与将null当作文字值进行比较。
亚伦·麦克弗

通常,您不能重载运算符,因为您只能在自己的类中定义它们。因此,在这种情况下,您将需要访问Nullable<T>的代码。
ANeves认为SE是邪恶的,2011年

0

NULL不为零(数字或二进制值),长度为零的字符串或空白(字符值)。因此,任何比较运算符都将始终对其返回false。 在这里了解更多


8
数据库NULL不是C#null。此外,C#可空类型的比较运算符是一种奇怪的野兽,不一定遵循用于空比较的常规规则。
Joren 2010年

3
答案仍然是正确的,只是链接是错误的。msdn.microsoft.com/zh-CN/library/2cf62fcy.aspx#sectionToggle4
unholysampler 2010年

5
@unholy:答案是错误的,更重要的是,它是基于错误的推理。
Joren 2010年

0

您期望什么值?

null == null是

null> = null否

null> null否

null <= null否

null <null否

null!= null否

1 == null否

1> = null否

1> null否

1 <=空false

1 <null否

1!= null tr​​ue又名!(1 == null)


0

> =仅以明确定义的特定方式使用时表示“大于或等于”。当在带有重载运算符的类上使用时,它表示类开发人员想要其含义的任何内容。当应用于类似字符串的类时,它的意思可能是“排序相同或更高”,或者可能意味着“长度相同或更长”。


0

由于默认情况下,aint不能为null,其值将设置为0,>和<的运算符是针对int类型构建的,因此期望与values或不与nulls

看到我对类似问题的回答,其中我写了一些nullable int使用less <greater >运算符处理的方法https://stackoverflow.com/a/51507612/7003760

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.