【问题标题】:Is Nullable<T>.Equals Method Implementation Wrong?Nullable<T>.Equals 方法实现是否错误?
【发布时间】:2009-10-08 23:40:23
【问题描述】:

我这里说的是 C# 语言。

msdn中Object.Equals(Object)方法的定义是:

判断是否指定 对象等于当前对象。

如果两个对象相等,则返回 true,如果它们为 null,则返回 false:

x.Equals(一个空引用 (Nothing in Visual Basic)) 返回 false。

为什么?因为 null 不是对象。

如果对象参数为空,则抛出 NullReferenceException。

我们还有这个:

x.Equals(y) 返回与 y.Equals(x)。

到这里完全没问题。它与 Java 非常相似。但是 C# 还为不可为空的类型提供了一个 System.Nullable 结构。据我所知,结构是一个对象。它继承了 Object.Equals 方法。

如果我有这样的结构:

struct Car
    {
        public string Make;
        public string Model;
        public uint Year;

        public Car(string make, string model, uint year)
        {
            Make = make;
            Model = model;
            Year = year;
        }
    }

并创建四个实例:

Car car1 = new Car("make", "model", 2009);
Car car2 = new Car("make", "model", 2009);
Car car3 = new Car("make", "model", 2008);

car1.Equals(car2); // will return true
car1.Equals(car3); // will return false;

据我所知,我们不能将结构设置为空值。但是 System.Nullable 是一个结构体,我们可以编译它而不会出现任何错误:

int? i = null;

(我也希望有人能解释一下。是结构体还是别的什么?)

我真正的问题是:

i.Equals(null); // returns true!

(通常 x.Equals(y) = y.Equals(x) 当然 null.Equals(i) 在这里无效...)

很明显 Object.Equals 方法在这里被覆盖了。也许它已记录在案并且已指定。但是这种方法正确/不错吗?如果是这样,== 和 Equals 方法对于 Nullable 值有什么区别?

【问题讨论】:

  • 回答您的最后一个问题。如果Car? ncar1 = ...;Nullable&lt;&gt;,那么ncar1 == nullncar1.Equals(null) 通常是相同的。两者都会检查ncar1.HasValue 是否为false。但是如果我们也有Car? ncar2 = ...;,那么ncar1 == ncar2ncar1.Equals(ncar2)可能会有所不同,这取决于Car 结构类型是否重载operator == .Equals 的重载(可能是 .Equals(object)Car 覆盖,或者只是被 System.ValueType 覆盖,或者如果声明了重载,则可能是 .Equals(Car))。

标签: c# oop


【解决方案1】:

我认为您的困惑源于以下一行

i? = null;

这实际上并没有创建空值变量。它本质上是以下的合成糖

Nullable<int> i = new Nullable<int>();

i 上的结果属性 HasValue 的值为 false。它不是 null 而是具有空值的值类型。或者只是一个空的可空值。恕我直言,考虑这一点的最佳方法是对于任何给定的 T,null 都可以转换为空的Nullable&lt;T&gt;

知道它使 i.Equals(null) 行更容易理解。它是以下的合成糖

Nullable<int> i = new Nullable<int>();
i.Equals(null);

Nullable&lt;T&gt; 类型仅覆盖 Equals(object)。尽管此方法的实现认为空值等于空的可空值。所以它的行为是正确的。

【讨论】:

  • 但是,无论它在后台做什么,我们都调用 i.Equals(null),当 i 为 null 时它返回 true。它应该为任何其他对象返回 false。
  • @jcasso,Nullable 的一般......很奇怪,并且经常以意想不到的方式表现。部分困惑是 i 永远不能为空,因为它实际上是一个值类型。最好将其视为空的可空值。
  • 至少你承认这很奇怪 :) 我以为只有我一个。
  • 请注意,static 方法Object.Equals(null, null) 将返回true,因此可以确定null 等于null。调用null.Equals(y) 时得到NullReferenceException 的唯一原因是引用类型上实例方法调用的语义要求;它与Equals 本身的语义无关。由于Nullable&lt;T&gt; 不是引用类型,因此不适用。
  • 就像我在另一篇文章中指出的那样,i.Equals(null) 没有调用 Object.Equals。这是一个限制为 Nullable 类型的虚拟调用。
【解决方案2】:

为了回答您的附带问题,Nullable 是一个带有 T: Struct 约束的结构。所以,即使 int?我=空;为 null,i 是 Nullable 结构的一个实例。

【讨论】:

  • 一个结构可能取空值?你能定义 Car car4 = null; ?
  • 就 CLR 而言,结构不能有 null 值。在 C# 中,当您编写 int? x = null 时,实际上是在编写 int? x = new int?()。那里根本没有真正的null
  • 没有。但是当你做int? i = >,CLR 将该合法值放入 i 的 value 属性中。另外,仅供参考,Nullable 会覆盖 Equals 方法
  • 另外,查看调用 int 下的 IL?我=空; CLR 加载它分配给变量的地址,然后将一个空的 Nullable 对象(带有 null 字段)初始化到该地址中。
  • @pavel:更简洁的方式来表达我在第二条评论中想说的话:)
猜你喜欢
  • 2012-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-22
  • 2012-10-01
  • 1970-01-01
相关资源
最近更新 更多