为啥在这种情况下可空类型不相等?

Posted

技术标签:

【中文标题】为啥在这种情况下可空类型不相等?【英文标题】:Why nullable types will not be equal in this case?为什么在这种情况下可空类型不相等? 【发布时间】:2009-04-24 11:30:15 【问题描述】:

令人惊讶的是下面的代码不会成功。

int? n1 = null;
int? n2 = null;
Assert.IsTrue(n1 <= n2);  // Fails here

你知道为什么吗?

【问题讨论】:

你的例子可能更好地问为什么 (null >= null) 是假的,将 nullable 带入这会使问题更加复杂,因为现在你需要讨论如何将 null 与不可为空的类型。 meandmycode,好点。我没有意识到 (null >= null) 是错误的。但深入研究后,我意识到 CLR 在幕后使 (null >= null) 成为可为空的表达式。 【参考方案1】:

在 C#(和 VB.Net)中使用具有可为空值的布尔逻辑通常会违反逻辑。我发现理解它的最好方法是记住“null 不是值”。因为 null 不是一个值,所以您不能对其进行任何操作。因此,像“1 &gt; null”和“1 &lt; null”这样的东西都是真的。

这里有详细指南:http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx

如果您确实想将 null 视为一个值,那么您可以使用 GetValueOrDefaultMethod() 将 null 等同于默认值。例如

Assert.IsTrue(n1.GetValueOrDefault() <= n2.GetValueOrDefault());  // True

这有点冗长,但可以完成工作。

【讨论】:

【参考方案2】:

要么这是一个错字,你的意思是“==”而不是“

在几乎所有语言(包括 c#)中,对 null 的唯一默认合法操作是检查其他内容是否等于它(在 .Net 中 == 默认为引用相等)。

= 没有意义(因为如果这样做,它们的行为会很奇怪)

某些语言(SQL 可能是最广为人知的)不允许使用“标准”相等运算符,以使这一点更加清晰。在 SQL 中 null == null 不正确,兼容的服务器将拒绝您尝试通过文字执行此操作的查询。

C# 采用与它的传统(C 风格命令式语言)相同的路线,其中对空值的测试基于测试其中的位是否为零(事情变得有些复杂,但基本上就是这样)。因此,只有引用类型才能真正为 null(Nullable&lt;T&gt; 在幕后有很多魔力让它看起来像,但实际上在引擎盖下它不是 null)。这意味着引用相等语义很好地遵循 null 语义,因此 == null 是允许的。

其他语言以不同的方式实现 null(例如 SQL,其中任何东西都可以设为 null,因此必须将某些东西的“nullness”存储在它之外(很像 Nullable)。这意味着传统的相等使用不需要是主要关注点,并且 null 可以是真正特殊的,而不是某些类型的特殊情况。 有关 null 特殊性的更多信息,请查看This question has a list of such languages

大多数引用类型没有定义 >= 或 = 也是)。

【讨论】:

这有点令人困惑的是 C# 与 SQL。在 C# 等编程语言中,null == null。但在 SQL 中,没有什么是真的——NULL=NULL、NULL!=NULL 等等。 我想向您保证,这不是错字。我的意思是“ 是的。 Null 是“特殊的”。 ***.com/questions/75267/… 许多语言中更严格的特殊性约束的优点 - 集成到答案中......【参考方案3】:

你可以试试这个:

int? n1 = null;
int? n2 = null;

// Test for equality
Assert.IsTrue((n1.HasValue && n2.HasValue && n1.Value == n2.Value) || (!n1.HasValue && !n2.HasValue));

// Test for less than or equal to
Assert.IsTrue(n1.HasValue && n2.HasValue && n1.Value <= n2.Value);

【讨论】:

原来的测试是:n1.Value 【参考方案4】:

Nullable 类型被包装到 System.Nullable 对象中,因此您无需比较 int 值,而是比较引用。要比较这些值,您需要这样做:

Assert.IsTrue(n1.Value <= n2.Value);

我在blog 上写了一些关于可空性的内容。

编辑: 但在您的情况下,n1 和 n2 为空,因此您甚至无法比较这些值。

【讨论】:

这取决于你想要做什么,如果这些引用之一为空。让我假设 null 也是无效的,所以它看起来像这样: Assert.IsTrue(n1 != null && n2 != null && n1.Value

以上是关于为啥在这种情况下可空类型不相等?的主要内容,如果未能解决你的问题,请参考以下文章

可空类型和三元运算符:为啥是`? 10:null`禁止? [复制]

C#进阶系列18 可空值类型

可空接收器类型捆绑的不安全使用? android 应用程序将在编译时出现警告但立即崩溃

可空类型

何时在启用可空引用类型的情况下对参数进行空检查

C# 中可空类型的替代方案