等于与另一个可空类型的可空类型进行比较

时间:2011-11-23 21:41:47

标签: c#

我有两个(同一类型的)对象,其中包含myprop类型的道具byte?。属性设置为null。当我执行objectA.myprop.Equals(objectB.myprop)时,我得到'true',尽管MSDN代码示例声明“应用于任何null对象的Equals返回false。”

我猜C#使用单独的重载进行可空类型比较。我想知道在这种情况下C#如何在内部处理对象与可空类型。

4 个答案:

答案 0 :(得分:5)

当你这样称呼它时,它会使用Nullable<T>.Equals(object)来显示文档中的预期行为:

(如果......,则返回值为true

  

HasValue属性为false,另一个参数为null。也就是说,根据定义,两个空值相等。

同样通过==进行平等,C#4规范(提升运算符)的7.3.7节说明:

  

对于等于运算符== [和] !=,如果操作数类型都是非可空值类型且结果类型为bool,则存在提升形式的运算符。提升形式是通过添加一个?每个操作数类型的修饰符。 提升的运算符认为两个空值等于,并且空值不等于任何非空值。如果两个操作数都是非null,则提升的运算符将解包操作数并应用基础运算符来生成bool结果。

(强调我的。)

编辑:现在我实际上不同意这里接受的答案,它说它不是一般规则。就object.Equals

的实施而言, 是一般规则
  

以下语句必须适用于Equals方法的所有实现。在列表中,x,y和z表示非空的对象引用。

     

[...]

     
      
  • x.Equals(null)返回false。
  •   

因此,虽然 是一般规则,但它并不适用于此特定情况 - 因为此处的值不是对象引用 - 它是值类型值。它仍然有点令人惊讶,除非你基本上接受Nullable<T>有点特殊情况 - 它具有特定的C#编译器支持它在拳击方面具有CLR支持开箱。

答案 1 :(得分:4)

为了清晰起见,我对此进行了编辑。

你误解了这句话。给出完整的背景:

string s = null;
string t = String.Empty; // Logically the same as ""

// Equals applied to any null object returns false.
bool b = (t.Equals(s));

这表示对string对象的引用不等同于null引用。您将该引用脱离了上下文,并将其解释为一般规则,但事实并非如此。但是,这是指引用不可为空的类型。

当你处理可以为空的原始类型时:

实际规则是

  

两个可为null的可空类型的相等比较   评估为真。

http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx

答案 2 :(得分:2)

Nullable类型是一个结构,结构永远不会得到一个null 值,所以当一个可空类型等于null时,这意味着这个变量实际上不是null而是隐式的强制转换< / strong>发生并且该变量使用属性Value = null 强制转换为值类型(可为空)。所以:

int? a=null;//(a) get a memory space with value property = null
a.GetHashcode();//if (a) really is null must throw a exception but not throw 

答案 3 :(得分:0)

我认为 Nullable 比较 X==Y 的行为完全符合直觉预期,但我感觉这里可能对 X.Equals(Y) 产生误解,它的行为好像是 {{1 }} 方法调用。

static

引用“应用于任何空对象的相等返回 false。” 对于 非静态 方法 object A, B; MyStruct? X, Y; 为真,并且通常应适用于任何明智地覆盖它。

然而,唯一的原因是,A.Equals(B) 是属于 A.Equals非静态方法,这意味着 A 永远不可能是 { {1}}。用 A 尝试 null 确实会抛出 A.Equals(B)

之所以如此,是因为A = null 引用的实例可能比声明的变量具有更具体的类型 {{1 }},而这种更具体的类型又可能会覆盖 NullReferenceException 方法。换句话说,如果 A 为 null,则运行时不知道要使用 A 的哪个实现,因此必须抛出 A.Equals

然而,静态方法不能被覆盖,这意味着 A 可以是 A.Equals 因为要运行的方法在编译时就已经知道了——时间。 (这就是为什么调用静态方法比调用非静态方法要快一点,也是为什么编译器可能决定内联一些静态调用,但我离题了。)

因此,对于任何 static 实现,两个操作数都可以是 Exception。此外,A 应始终被视为与 null 相同,并且与任何其他值不同。 (如果 null 的实现偏离了这个常见的假设,那么这通常会被视为错误。)

静态 null 方法示例:

null

在这方面,Equals 的行为方式与对象相同。唯一的区别是 Equals 支持 X 或 Y 或两者为空而不抛出异常。所以更准确地说,它的行为类似于上面提到的静态相等方法,这通常更可取。

但是 A==B; A!=B; MyClass.Equals(A, B); object.Equals(A, B); ReferenceEquals(A, B); 怎么可能表现得像一个静态方法?这是因为 Nullable 是一个结构体。 C#中的Structs不支持继承,所以变量的类型和实例的类型没有区别。这就是为什么运行时永远不会怀疑 Equals 指的是哪个方法。所以不需要异常。因此,该结构支持的任何值都可以为两个操作数的方法所支持,因此 X.Equals(Y) 只是另一个值。

现在,除此之外,还有一些对语法糖和 X.Equals(Y) 类型优化的内置特殊支持,但据我所知,行为仍然存在,如上所述。