Following Guidelines for Overriding Equals() and Operator == (C# Programming Guide), it seems advisable to override gethashcode when overriding equals(object), as well as equals(type).
It is in my understanding that there is an endless discussion about what's the best implementation for overriding Equals. However, I still like to understand the Equals concept a little better and decide for my own.
My questions will probably be kinda noobish, but here we go:
What is the main difference between Equals(object) and Equals(type) (independently of the given parameters)?
As far as I understand (And I could be completely wrong, so this is a question at the same time):
Equals(object) is a build in method that looks (at default) if object
references are the same. And Equals(Type) is a local method you
create. So in fact, what you have in that class is the method Equals
with 2 overloads.
Why do they check for property equality twice?
In equals(object) :
return base.Equals(obj) && z == p.z;
and in equals(type) :
return base.Equals((TwoDPoint)p) && z == p.z;
Why is it advisable to implement the Equals(type) method?
Most of my questions are rapped in my statement in question 1. So note any wrong or misleading arguments plz. Also, feel free to add any information, it will certainly help.
Thanks in advance
First lets distinguish the 2 methods
object.Equals() is a method on the root object which is marked as virtual and therefore can be overriden in a derived class.
IEquatable<T>.Equals is a method obtained by implementing the IEquatable<T> interface.
The latter is used for determining equality inside a generic Collection; so say the documentation:
The IEquatable<T> interface is used by generic collection objects such as Dictionary<TKey, TValue>, List<T>, and LinkedList<T> when testing for equality in such methods as Contains, IndexOf, LastIndexOf, and Remove. It should be implemented for any object that might be stored in a generic collection.
The former is used for determining equality everywhere else.
So with the groundwork in place lets try to answer some of your specific questions
What is the main difference between Equals(object) and Equals(type) (independently of the given parameters)?
One operates on any type, the other compares instances of the same type
Why do they check for property equality twice?
They dont, generally only one is used. However quite often one implementation calls the other internally
Why is it advisable to implement the Equals(type) method?
The answer is above - if you intend to store the object in a generic collection
As a side note, and one which may help you understand this, the default behaviour of equality checking is to check that the references are the same (ie, that one object is exactly the same instance as another). Quite often overriding/implementing different equality logic is used to compare some data within fields of the object (akin to your example of z == p.z)
One difference between the overloads is that, as noted, one will be invoked when comparing an object to things which are known at compile time to be of the same type, while the other will be invoked in all other circumstances. Another very important difference which has not been mentioned is that Equals(ownType) will act not only on things of ownType, but also on things that are implicitly convertible to ownType. Because of this, Equals cannot not be expected to implement an equivalence relation among objects of convertible types unless one forces its operands to be of type Object. Consider, for example,
(12.0).Equals(12);
converts the integer value 12 to the Double value 12.0. Since the type and value of the passed value precisely match the 12.0 whose Equals method is being invoked, thus returning true.
(12).Equals(12.0);
Because Double is not implicitly convertible to Int32, passes the Double value as Object instead. Since the Double does not match the type of the 12 whose Equals method is being invoked, the method returns false.
The virtual method Equals(Object) implements an equivalence relation; in many cases involving implicit type conversions, the type-specific methods cannot be expected to do so.
Related
This question already has answers here:
What is "Best Practice" For Comparing Two Instances of a Reference Type?
(9 answers)
Closed 6 years ago.
This MSDN article spells out when to declare a type as a value type (struct) vs a reference type (class). In particular, it says:
AVOID defining a struct unless the type has all of the following characteristics:
It logically represents a single value, similar to primitive types (int, double, etc.).
It has an instance size under 16 bytes.
It is immutable.
It will not have to be boxed frequently.
In all other cases, you should define your types as classes.
Then, this MSDN article spells out some guidelines for overriding Object.Equals() on a type, including:
When a type is immutable, ... overloading operator == to compare value equality instead of reference equality can be useful because, as immutable objects, they can be considered the same as long as they have the same value. It is not a good idea to override operator == in non-immutable types.
So it seems to me, if a type is meant to be immutable, you would just declare it a struct and override ValueType.Equals(). But, if your type is declared a class, you only want reference semantics, in theory. This SO post seems to support that. So my question is, why would you ever bother overriding Equals() on a reference type? Doing so is like saying that reference semantics aren't good enough for your reference type, which makes no sense to me. The only example I can think of is if you have a large (>16 byte instances) class that has a mix of mutable and immutable fields, but even then it seems like reference semantics would be all you need.
To your specific question - "why would you ever bother overriding Equals() on a reference type?": You would override Equals() if you want two instances of the class to be treated as equal by other .NET methods even if they are not the same instance.
Consider List<T>.Contains(). By overriding Equals() you can ensure that method gives you the correct result even if the specific class instances being compared are not in fact the same instance.
I myself encountered this a lot in WPF. I had a situation where certain controls (ListBox in particular) had copies of my objects that were not the same instances as what I was testing them against. This made methods like ScrollIntoView, and the SelectedItem property, not work correctly until I overrode Equals on the class. I can think of one particular example where this would for sure happen: suppose you had a Person class with a list of instances that were created as a result of a database query. You fill a ListBox with that result set. Then later on, you have a new result set from a different DB query (a filter of some kind, perhaps), and now want to select all the items in the ListBox that are in the second query result. If you don't override Equals, then you won't just be able to set SelectedItems, because the instances in your ListBox won't be the same as the instances in that second query. As is pointed out in the comments, there are other ways around this, but in my opinion overriding Equals offers the cleanest solution.
That's just one example. I'm sure you will encounter others before long.
Attempt #3 to simplify this question:
A generic List<T> can contain any type - value or reference. When checking to see if a list contains an object, .Contains() uses the default EqualityComparer<T> for type T, and calls .Equals() (is my understanding). If no EqualityComparer has been defined, the default comparer will call .Equals(). By default, .Equals() calls .ReferenceEquals(), so .Contains() will only return true if the list contains the exact same object.
Until you need to override .Equals() to implement value equality, at which point the default comparer says two objects are the same if they have the same values. I can't think of a single case where that would be desirable for a reference type.
What I'm hearing from #Enigmativity is that implementing IEqualityComparer<StagingDataRow> will give my typed DataRow a default equality comparer that will be used instead of the default comparer for Object – allowing me to implement value equality logic in StagingDataRow.Equals().
Questions:
Am I understanding that correctly?
Am I guaranteed that everything in the .NET framework will call EqualityComparer<StagingDataRow>.Equals() instead of StagingDataRow.Equals()?
What should IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj) hash against, and should it return the same value as StagingDataRow.GetHashCode()?
What is passed to IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)? The object I'm looking for or the object in the list? Both? It would be strange to have an instance method accept itself as a parameter...
In general, how does one separate value equality from reference equality when overriding .Equals()?
The original line of code spurring this question:
// For each ID, a collection of matching rows
Dictionary<string, List<StagingDataRow>> stagingTableDictionary;
StagingTableMatches.AddRange(stagingTableDictionary[perNr].Where(row => !StagingTableMatches.Contains(row)));
.
Ok, let's handle a few misconceptions first:
By default, .Equals() calls .ReferenceEquals(), so .Contains() will only return true if the list contains the exact same object.
This is true, but only for reference types. Value types will implement a very slow reflection-based Equals function by default, so it's in your best interest to override that.
I can't think of a single case where that would be desirable for a reference type.
Oh I'm sure you can... String is a reference type for instance :)
What I'm hearing from #Enigmativity is that implementing IEqualityComparer<StagingDataRow> will give my typed DataRow a default equality comparer that will be used instead of the default comparer for Object – allowing me to implement value equality logic in StagingDataRow.Equals().
Err... No.
IEqualityComaprer<T> is an interface which lets you delegate equality comparison to a different object. If you want a different default behavior for your class, you implement IEquatable<T>, and also delegate object.Equals to that for consistency. Actually, overriding object.Equals and object.GetHashCode is sufficient to change the default equality comparison behavior, but also implementing IEquatable<T> has additional benefits:
It makes it more obvious that your type has custom equality comparison logic - think self documenting code.
It improves performance for value types, since it avoids unnecessary boxing (which happens with object.Equals)
So, for your actual questions:
Am I understanding that correctly?
You still seem a bit confused about this, but don't worry :)
Enigmativity actually suggested that you create a different type which implements IEqualityComparer<T>. Looks like you misunderstood that part.
Am I guaranteed that everything in the .NET framework will call EqualityComparer<StagingDataRow>.Equals() instead of StagingDataRow.Equals()
By default, the (properly written) framework data structures will delegate equality comparison to EqualityComparer<StagingDataRow>.Default, which will in turn delegate to StagingDataRow.Equals.
What should IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj) hash against, and should it return the same value as StagingDataRow.GetHashCode()
Not necessarily. It should be self-consistent: if myEqualitycomaprer.Equals(a, b) then you must ensure that myEqualitycomaprer.GetHashCode(a) == myEqualitycomaprer.GetHashCode(b).
It can be the same implementation than StagingDataRow.GetHashCode, but not necessarily.
What is passed to IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj)? The object I'm looking for or the object in the list? Both? It would be strange to have an instance method accept itself as a parameter...
Well, by now I hope you've understood that the object which implements IEqualityComparer<T> is a different object, so this should make sense.
Please read my answer on Using of IEqualityComparer interface and EqualityComparer class in C# for more in-depth information.
Am I understanding that correctly?
Partially - the "default" IEqualityComparer will use either (in order):
The implementation of IEquatable<T>
An overridden Equals(object)
the base object.Equals(object), which is reference equality for reference types.
I think you are confusing two different methods of defining "equality" in a custom type. One is by implementing IEquatable<T> Which allows an instance of a type to determine if it's "equal" to another instance of the same type.
The other is IEqualityComparer<T> which is an independent interface that determines if two instance of that type are equal.
So if your definition of Equals should apply whenever you are comparing two instances, then implement IEquatable, as well as overriding Equals (which is usually trivial after implementing IEquatable) and GetHashCode.
If your definition of "equal" only applies in a particular use case, then create a different class that implements IEqualityComparer<T>, then pass an instance of it to whatever class or method you want that definition to apply to.
Am I guaranteed that everything in the .NET framework will call EqualityComparer<StagingDataRow>.Equals() instead of StagingDataRow.Equals()?
No - only types and methods that accept an instance of IEqualityComparer as a parameter will use it.
What should IEqualityComparer<StagingDataRow>.GetHashCode(StagingDataRow obj) hash against, and should it return the same value as StagingDataRow.GetHashCode()?
It will compute the hash code for the object that's passed in. It doesn't "compare" the hash code to anything. It does not necessarily have to return the same value as the overridden GetHashCode, but it must follow the rules for GetHashCode, particularly that two "equal" objects must return the same hash code.
It would be strange to have an instance method accept itself as a parameter...
Which is why IEqualityComparer is generally implemented on a different class. Note that IEquatable<T> doesn't have a GetHashCode() method, because it doesn't need one. It assumes that GetHashCode is overridden to match the override of object.Equals, which should match the strongly-typed implementation of IEquatable<T>
Bottom Line
If you want your definition of "equal" to be the default for that type, implement IEquatable<T> and override Equals and GetHashCode. If you want a definition of "equal" that is just for a specific use case, then create a different class that implements IEqualityComparer<T> and pass an instance of it to whatever types or methods need to use that definition.
Also, I would note that you very rarely call these methods directly (except Equals). They are usually called by the methods that use them (like Contains) to determine if two objects are "equal" or to get the hash code for an item.
This question already has answers here:
Should an override of Equals on a reference type always mean value equality?
(3 answers)
Closed 7 years ago.
Let's consider Polygon class. Check for equality should compare references most of the time, but there are many situations where value equality comes in handy (like when one compares two polygons with Assert.AreEqual).
My idea is to make value equality somewhat secondary to reference equality. In this case it's pretty obvious that ==operator should keep its default reference check implementation.
What about object.Equals() and IEquatable<Polygon>.Equals() then? MSDN doesn't imply that == and .Equals() should do the same but still - wouldn't it make the behavior of Polygon objects too ambiguous?
Also, the Polygon class is mutable.
MSDN is almost clear about it
To check for reference equality, use ReferenceEquals. To check for
value equality, you should generally use Equals. However, Equals as it
is implemented by Object just performs a reference identity check. It
is therefore important, when you call Equals, to verify whether the
type overrides it to provide value equality semantics. When you create
your own types, you should override Equals.
By default, the operator == tests for reference equality by
determining if two references indicate the same object, so reference
types do not need to implement operator == in order to gain this
functionality. When a type is immutable, meaning the data contained in
the instance cannot be changed, overloading operator == to compare
value equality instead of reference equality can be useful because, as
immutable objects, they can be considered the same as long as they
have the same value. Overriding operator == in non-immutable types is
not recommended.
IEquatable documentation is also very clear
Defines a generalized method that a value type or class implements to
create a type-specific method for determining equality of instances.
A major difficulty with equality testing in .NET (and also Java) is that there are two useful equivalence relations, each based on a question that can be sensibly asked of any class object, but .NET isn't consistent about which question or relationship should be encapsulated by Equals and GetHashCode supposed to answer. The questions are:
Will you always and forever be equivalent to the object identified by some particular reference, no matter what happens to you.
Will you consider yourself equivalent to the object identified by some particular reference unless or until something with a reference to you does something that would affect that equivalence.
For immutable objects, both relationships should test value equality. For mutable objects, the first question should test referential equivalence and the second should test value equality. For an immutable object which holds a reference to an object which is of mutable type, but which nobody will ever mutate, both questions should test value equality of that encapsulated object.
My personal recommendation would be that mutable objects not override Object.Equals, but that they provide a static property that returns an IEqualityComparer which tests value equality. This would require that
any object that immutably encapsulates the mutable object will have to
get that IEqualityComparer to be able to report the encapsulated object's
value-equivalence relation as its own, but having an IEqualityComparer
would make it possible to store such things in e.g. a Dictionary provided
they are never modified.
I was reading the MSDN documentation about object.Equals. in the remarks part it mentioned:
If the two objects do not represent the same object reference and
neither is null, it calls objA.Equals(objB) and returns the result.
This means that if objA overrides the Object.Equals(Object) method,
this override is called.
My question is why they did not implement this part as objA.Equals(objB) && objB.Equals(objA) to make equality symmetric and just relate on one side of the relation? It can result in strange behaviors when calling object.Equals.
EDIT: Strange behavior can happen when type of objA overrides Equals method and implemented it as something not predictable, but type of objB does not override Equals.
Basically, this would only be of any use to developers with flawed Equals implementations. From the documentation:
The following statements must be true for all implementations of the Equals(Object) method. In the list, x, y, and z represent object references that are not null.
[...]
x.Equals(y) returns the same value as y.Equals(x).
[...]
So the check is redundant in every case where the method has been correctly implemented - causing a performance hit to every developer who has done the right thing.
It isn't even terribly useful to developers who haven't done the right thing, as they may still expect object.Equals(x, y) to return true when it returns false - they could debug and find that their method returns true, after all. You could say that it would be documented to check both ways round - but we've already established that the only developers this affects are ones who don't read the documentation anyway.
Basically, when you override a method or implement an interface, you should know what you're doing and obey the specified contract. If you don't do that, you will get odd behaviour, and I don't think it's reasonable to expect every caller to try to work around implementations which don't do what they're meant to.
This is not a question how to implement it but what is the purpose of this method? I mean -- OK, I understand that is needed when searching, but why it is buried as an method of "object" class?
The story goes -- I have classes which objects are not comparable by default (in logical sense). Each time you want to compare/search for them you have to specify exactly how matching is done. The best in such case would be:
there is no such ubiquitous method as Equals, problem solved, no programmer (user of my class) would fall in trap by omitting custom match when searching
but since I cannot change C#
hide inherited, unwanted methods to prevent the call (compile-time)
but this also would require change to C#
override Equals and throw exception -- at least programmer is notified in runtime
So I am asking because I am forced to ugly (c), because (b) is not possible and because of lack of (a).
So in short -- what is the reason of forcing all objects to be comparable (Equals)? For me it is one assumption too far. Thank you in advance for enlightenment :-).
I agree that it was basically a mistake, in both .NET and Java. The same is true for GetHashCode - along with every object having a monitor.
It made a bit more sense before generics, admittedly - but with generics, overriding Equals(object) always feels pretty horrible.
I blogged about this a while ago - you may find both the post and the comments interesting.
You forgot option 4.: Do nothing, let the default reference equality take place. No big deal IMO. Even with your custom match options, you could choose a default option (I'd go for the most strict option) and use it to implement Equals().
Suppose someone has a List of Animal, and one wishes to compare two items against each other: an instance of Cat and an instance of Dog. If the Cat instance is asked whether it is the same as the Dog instance, does it make more sense for the cat to throw an InvalidTypeException, or for it to simply say "No, it's not equal".
An Equals method is supposed to obey two rules:
Reciprocity of equality: For any X and Y, X.Equals(Y) will be true if and only if Y.Equals(X) is true.
Liskov Substitution Principle: If class Q derives from P, an operation that can be done with a Q may also be done with a P.
These together imply that if Q derives from P, it must be possible for an object of type P to call Equals on an object of type Q, which in turn implies that it must be possible for an object of type Q to call Equals on an object of type P. Further, if R also derives from P, it must be possible for an object of type Q to call Equals on an object of type R (whether or not R is related to Q).
While it may not be strictly necessary for all objects to implement Equals, it's much cleaner for all classes to have a single Equals(Object) than to have a variety of Equals methods for different base types, all of which must be overridden with identical semantics to avoid weird behaviors.
Edit/Addendum
Object.Equals exists to answer the question: given two object references X and Y, can object X promise that outside code which doesn't use ReferenceEquals, Reflection, etc. would be unable to show that X and Y do not refer to the same object instance? For any object X, X.Equals(X) must be true since outside code cannot possibly show that X is not the same instance as X. Further, if X.Equals(Y) is "legitimately" true, Y.Equals(X) must also be true; if not, the fact that X.Equals(X) (which is true) doesn't match Y.Equals(X) would be a demonstrable difference implying that X.Equals(Y) should be false.
For shallowly-mutable types, if X and Y refer to different object instances, one could generally demonstrate this by mutating X and observing whether the same mutation occurred in Y(*). If such mutation could be used to demonstrate that X and Y are different object instances, then X.Equals(Y) should return true. The reason two String objects containing the same characters will report themselves equal to each other is not just that they happen to contain the same characters at the time of comparison, but more significantly that if all instances of one were replaced with the other, only code that used ReferenceEquals, Reflection, or other such tricks, would even notice.
(*) It would be possible to have two distinct but indistinguishable instances X and Y of a shallowly-mutable class which both held references to each other, such that methods that would mutate one would also mutate the other. If there would be no way for outside code to distinguish the instances apart, one might legitimately have X.Equals(Y) report true (and vice versa). On the other hand, I can't think of any way such a class would be more useful that one in which both X and Y held immutable references to a shared mutable object. Note that X.Equals(Y) does not require that X and Y to deep-immutable; it merely requires that any mutations applied to X will have identical effects on Y.