什么时候a == b可以是假的而a.Equals(b)是真的吗?

我今天遇到了这种情况。 我有一个我正在测试平等的对象; Create()方法返回MyObject的子类实现。

MyObject a = MyObject.Create(); MyObject b = MyObject.Create(); a == b; // is false a.Equals(b); // is true 

注意我还在子类实现中覆盖了Equals(),它执行了一个非常基本的检查,以查看传入的对象是否为null并且是子类的类型。 如果满足这两个条件,则认为对象是相等的。

另一个有点奇怪的是我的unit testing套件做了一些类似的测试

 Assert.AreEqual(MyObject.Create(), MyObject.Create()); // Green bar 

并观察到预期的结果。 因此,我猜NUnit在封面下使用a.Equals(b),而不是像我假设的那样使用== b。

旁注:我使用.NET和Java混合编程,所以我可能会在这里混淆我的期望/假设。 但是,我认为a == b在.NET中的工作比在Java中更为一致,在Java中,您经常必须使用equals()来测试相等性。

更新以下是Equals()的实现,如下所示:

 public override bool Equals(object obj) { return obj != null && obj is MyObjectSubclass; } 

==Equals之间的关键区别是== (像所有运算符一样)不是多态的 ,而Equals (就像任何虚函数一样)是。

默认情况下,引用类型将获得==Equals相同结果,因为它们都比较引用。 当然也可以用完全不同的方式编写运算符逻辑和Equals逻辑,尽管这似乎是荒谬的。 最大的问题来自于在更高级别使用== (或任何)运算符而不是声明所需的逻辑(换句话说,将对象引用为父类,要么没有明确定义运算符,要么以不同方式定义运算符。真正的课程)。 在这种情况下,它所引用的类的逻辑用于运算符,但Equals的逻辑来自对象实际上的任何类。

我想强调指出,完全基于你问题中的信息, 绝对没有理由认为或假设Equals比较价值与参考 。 创建这样一个类非常容易,但这不是语言规范。

后问题编辑编辑

对于类的任何非null实例,您Equals实现将返回true。 虽然语法让我觉得你不是,但你可能会混淆C#关键字(确认类型)和VB.NET中的is关键字(它确认了引用相等)。 如果确实如此,那么您可以使用Object.ReferenceEquals(this, obj)在C#中进行显式引用比较。

无论如何,这就是为什么你看到了Equals true ,因为你传入的是类的非null实例。

顺便提一下,你使用Equals对NUnit的评论是出于同样的原因; 因为运算符不是多态的,所以如果使用Assert函数==则特定类无法定义自定义相等行为。

a == b检查它们是否引用同一个对象。

a.Equals(b)比较内容。

这是2004年Jon Skeet文章的链接 ,可以更好地解释它。

你自己几乎回答了你的问题:

我还在子类实现中覆盖了Equals(),它执行了一个非常基本的检查,以查看传入的对象是否为null并且是子类的类型。 如果满足这两个条件,则认为对象是相等的。

==运算符没有被重载 – 所以它返回false因为ab是不同的对象。 但是a.Equals正在调用你的覆盖,这可能会返回true因为ab都不是null,并且它们都是子类的类型。

所以你的问题是“什么时候a == b可能是假的而a.Equals(b)是真的吗?” 在这种情况下你的答案是:当你明确地编码它时!

在Java中,a == b检查两个对象的引用是否相等(如果两个对象是同一个对象,则为“rouzed”)

a.equals(b)比较两个对象表示的值。

除非它们在对象内特别重载以执行其他操作,否则它们都会执行相同的操作。

其他地方提到的Jon Skeet文章的引用。

Equals方法只是在System.Object中定义的虚拟方法,并且被选择执行的任何类重写。 ==运算符是一个可以由类重载但通常具有标识行为的运算符。

这里的关键字是USUALLY 。 可以编写它们来做基础类所希望的任何事情,而且他们不必做同样的事情。

“==”操作测试绝对相等(除非超载); 也就是说,它测试两个对象是否是同一个对象 。 只有当你把一个分配到另一个时,这才是真的,即。

 MyObject a = MyObject.Create(); MyObject b = a; 

仅仅设置两个对象的所有属性并不意味着对象本身。 在引擎盖下,“==”运算符所比较的是内存中对象的地址。 这样做的实际效果是,如果两个对象真正相等,那么改变其中一个对象的属性也会改变另一个对象,而如果它们只相似(“等于”相等),则不会。 一旦理解了原理,这就完全一致了。

我相信a == b会检查引用的对象是否相同。

通常要查看值是否相同a.Equals(b)被使用(这通常需要被覆盖以便工作)。