When can a == b be false and a.Equals(b) true?
Asked Answered
F

7

25

I ran into this situation today. I have an object which I'm testing for equality; the Create() method returns a subclass implementation of MyObject.

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

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

Note I have also over-ridden Equals() in the subclass implementation, which does a very basic check to see whether or not the passed-in object is null and is of the subclass's type. If both those conditions are met, the objects are deemed to be equal.

The other slightly odd thing is that my unit test suite does some tests similar to

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

and the expected result is observed. Therefore I guess that NUnit uses a.Equals(b) under the covers, rather than a == b as I had assumed.

Side note: I program in a mixture of .NET and Java, so I might be mixing up my expectations/assumptions here. I thought, however, that a == b worked more consistently in .NET than it did in Java where you often have to use equals() to test equality.

UPDATE Here's the implementation of Equals(), as requested:

public override bool Equals(object obj) {
    return obj != null && obj is MyObjectSubclass;
}
Furniture answered 22/3, 2010 at 16:59 Comment(3)
Could we see your implementation of the .Equals() overrideNorwood
Please post the code for the overridden Equals function.Ultann
when one but not both is overriden of course :)Buckles
M
32

The key difference between == and Equals is that == (like all operators) is not polymorphic, while Equals (like any virtual function) is.

By default, reference types will get identical results for == and Equals, because they both compare references. It's also certainly possible to code your operator logic and Equals logic entirely differently, though that seems nonsensical to do. The biggest gotcha comes when using the == (or any) operator at a higher level than the desired logic is declared (in other words, referencing the object as a parent class that either doesn't explicitly define the operator or defines it differently than the true class). In such cases the logic for the class that it's referenced as is used for operators, but the logic for Equals comes from whatever class the object actually is.

I want to state emphatically that, based solely upon the information in your question, there is absolutely no reason to think or assume that Equals compares values versus references. It's trivially easy to create such a class, but this is not a language specification.

Post-question-edit edit

Your implementation of Equals will return true for any non-null instance of your class. Though the syntax makes me think that you aren't, you may be confusing the is C# keyword (which confirms type) with the is keyword in VB.NET (which confirms referential equality). If that is indeed the case, then you can make an explicit reference comparison in C# by using Object.ReferenceEquals(this, obj).

In any case, this is why you are seeing true for Equals, since you're passing in a non-null instance of your class.

Incidentally, your comment about NUnit using Equals is true for the same reason; because operators are not polymorphic, there would be no way for a particular class to define custom equality behavior if the Assert function used ==.

Myoglobin answered 22/3, 2010 at 17:8 Comment(2)
This is possibly the best answer I've ever had to any question I've asked on SO. Thanks Adam, I wish I could upvote you more than just the once!Furniture
+1 for addressing the Equals override after the OP updated the question with the code.Jurisprudence
D
6

a == b checks if they reference the same object.

a.Equals(b) compares the contents.

This is a link to a Jon Skeet article from 2004 that explains it better.

Deliadelian answered 22/3, 2010 at 17:1 Comment(10)
True for strings. Generalizing for other classes, a.Equals(b) returns the result of the Equals method of a.Calomel
Unless you overload the == operator. +1Shakhty
-1. There is absolutely no reason to assume that Equals here determines the equality based upon a deep inspection of the object's data.Myoglobin
@Michael: not true for strings. String overrides operator ==, so a == b compares contents, too.Orthodox
@nikie: The only difference would be if the string was being referenced in the context of an object, in which case string's implementation of == would not be used, but its implementation of Equals would.Myoglobin
I am baffled at the level of upvotes that this answer has received. Not only is it entirely incorrect, but Jon's article does not in any way support this position.Myoglobin
-1, I agree with Adam Robinson, this is only true if the class in question is written to make it true. It is in NO WAY an absolute truth.Watercool
The general meaning of .Equals is irrelevant anyway, since the OP explicitly states he's overridden it.Bale
@nikie: I was talking only about the Equals method, but I didn't express that well.Calomel
From that article: "The Equals method is just a virtual one defined in System.Object, and overridden by whichever classes choose to do so. The == operator is an operator which can be overloaded by classes, but which usually has identity behaviour." The important word being USUALLY.Watercool
B
3

You pretty much answered your question yourself:

I have also over-ridden Equals() in the subclass implementation, which does a very basic check to see whether or not the passed-in object is null and is of the subclass's type. If both those conditions are met, the objects are deemed to be equal.

The == operator hasn't been overloaded - so it's returning false since a and b are different objects. But a.Equals is calling your override, which is presumably returning true because neither a nor b are null, and they're both of the subclass' type.

So your question was "When can a == b be false and a.Equals(b) true?" Your answer in this case is: when you explicitly code it to be so!

Bale answered 22/3, 2010 at 17:21 Comment(5)
As a point of correction, operators are overloaded, not overridden (since they're static). There's no polymorphism with operators, so it would still be trivially easy to produce a scenario where identical logic in the == operator and Equals method would produce different results.Myoglobin
Ok, so by coding my objects in this way, have I explicitly broken Equals/==. Is this a code smell that indicates the design needs re-thinking?Furniture
@alastairs: If you want any two non-null instances of your type to be considered equal, then you've coded your function correctly.Myoglobin
@Adam thanks for the correction! I've fixed it in my answer (though left the original quote code intact).Bale
+1 Straightforward: it is clear from the overloaded Equals method that the OP's == operator is not going to give same results as .Equals(), regardless of the native language differences between == and .Equals()Herrenvolk
B
1

In Java a ==b check if the references of the two objects are equals (rougly, if the two objects are the same object "aliased")

a.equals(b) compare the values represented by the two objects.

Bacciferous answered 22/3, 2010 at 17:3 Comment(1)
True in Java, not always true in C#.Shakhty
W
1

They both do the same unless they are specifically overloaded within the object to do something else.

A quote from the Jon Skeet Article mentioned elsewhere.

The Equals method is just a virtual one defined in System.Object, and overridden by whichever classes choose to do so. The == operator is an operator which can be overloaded by classes, but which usually has identity behaviour.

The keyword here is USUALLY. They can be written to do whatever the underlying class wishes and in no way do they have to do the same.

Watercool answered 22/3, 2010 at 17:20 Comment(0)
M
0

I believe that a == b will check if the referenced object is the same.

Usually to see if the value is the same a.Equals(b) is used (this often needs to be overridden in order to work).

Momism answered 22/3, 2010 at 17:2 Comment(2)
Unless the class overrides operator==.Shakhty
This is incorrect. There is not a language-level semantic difference between == and Equals.Myoglobin
B
0

The "==" operate tests absolute equality (unless overloaded); that is, it tests whether two objects are the same object. That's only true if you assigned one to the other, ie.

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

Just setting all the properties of two objects equal doesn't mean the objects themselves are. Under the hood, what the "==" operator is comparing is the addresses of the objects in memory. A practical effect of this is that if two objects are truly equal, changing a property on one of them will also change it on the other, whereas if they're only similar ("Equals" equal), it won't. This is perfectly consistent once you understand the principle.

Bayonet answered 22/3, 2010 at 17:6 Comment(1)
This is true by default for reference types. It is not absolute truth.Myoglobin

© 2022 - 2024 — McMap. All rights reserved.