Nullable<int> 是“预定义的值类型”吗?或者 Equals() 和 == 如何在这里工作?

Posted

技术标签:

【中文标题】Nullable<int> 是“预定义的值类型”吗?或者 Equals() 和 == 如何在这里工作?【英文标题】:Is Nullable<int> a "Predefined value type" - Or how does Equals() and == work here? 【发布时间】:2014-08-05 23:38:20 【问题描述】:

对于我自己实现的 Equals() 方法,我想检查一堆内部字段。我是这样做的:

...
_myNullableInt == obj._myNullableInt &&
_myString == obj._myString &&
...

我会假设,这会比较值,包括 null,而不是对象地址(作为参考 euqality 比较操作),因为:

对于“预定义值类型”in this MSDN doc here 是这样说的。 我假设Nullable&lt;int&gt; 是这样一个“预定义值类型”,因为它在System 命名空间中,根据this MSDN doc。

我是否可以假设此处比较 VALUES?

注意:单元测试显示“是”,但我想通过这个问题让其他人放心,以防我错过了什么。

【问题讨论】:

【参考方案1】:

在 C# 中,有一个名为“Lifted Operators”的概念,在语言规范 (Version 5 download) 的第 7.3.7 节中有描述:

提升的运算符允许对不可为空值类型进行操作的预定义和用户定义的运算符也可用于这些类型的可空形式。 Lifted 算子由满足特定要求的预定义和用户定义的算子构成,如下所述

特别是:

对于等式运算符

==  !=

如果操作数类型都是不可为空的值类型并且结果类型是布尔值,则存在运算符的提升形式。提升的形式是通过添加单个 ?每个操作数类型的修饰符。提升的运算符认为两个空值相等,一个空值不等于任何非空值。如果两个操作数都不为 null,则提升的运算符解开操作数并应用底层运算符来生成 bool 结果。

因此,由于在ints 之间定义了一个== 运算符,因此也为int?s 定义了一个运算符

【讨论】:

谢谢,我实际上是在你提到的规范的章节中查到的。这给了我所希望的安心。【参考方案2】:

如果您比较这些值,它实际上会调用Nullable&lt;T&gt;.Equals 方法,因为这两个值都是可为空的整数。

Nullable&lt;T&gt;.Equals 最终会调用 int 的 == compare 关键字,如果两个值都不为 null。所以最后,它确实会检查这些值。

Equals 方法的代码很好地说明了这一点:

public override bool Equals(object other)

    if (!this.HasValue)
    
        return (other == null);
    
    if (other == null)
    
        return false;
    
    return this.value.Equals(other);

【讨论】:

其实是反过来的,Nullable&lt;T&gt;.Equals 最终调用了== 实际的值类型... 依次调用== 来获取预定义的值类型。见msdn.microsoft.com/en-us/library/53k8ybth.aspx、For predefined value types, the equality operator (==) returns true if the values of its operands are equal 不适用于预定义的值类型 :) 查看 IL :) int.Equals => return ((obj is int) &amp;&amp; (this == ((int) obj))); @flindeberg:相应地更新了我的答案。

以上是关于Nullable<int> 是“预定义的值类型”吗?或者 Equals() 和 == 如何在这里工作?的主要内容,如果未能解决你的问题,请参考以下文章

C# 反射:如何获取 Nullable<int> 的类型?

Nullable<T> 的内存占用是多少

如何使绑定到 Nullable<int> 属性的 DropDownListFor 接受空值?

了解下C# 可空类型(Nullable)

解析类型后加问号和双问号

C#--可空类型(Nullable)