do I need to override Equal? - c#

I've read some stuff about overriding Equal and GetHashcode but do I need it when just having a simple own Equal method like below?
And if I do have to override it:
Why is that? - Should I use Id.GetHashCode() when overriding GetHashCode()?
public class Foo {
public Guid Id { get; } = new Guid();
public bool Equal(Foo other) {
if (other == null) return false;
return Id == other.Id;
}
}

Your code looks like you want to implement IEquatable<Foo> for your object. And MSDN advice to oveeride Object.Equals() method:
If you implement IEquatable, you should also override the base
class implementations of Object.Equals(Object) and GetHashCode so that
their behavior is consistent with that of the IEquatable.Equals
method. If you do override Object.Equals(Object), your overridden
implementation is also called in calls to the static
Equals(System.Object, System.Object) method on your class. In
addition, you should overload the op_Equality and op_Inequality
operators. This ensures that all tests for equality return consistent
results.

Another pointer to your solution can be found here - It explains what all are your options -- please have a read
Typically, you implement value equality when objects of the type are
expected to be added to a collection of some sort, or when their
primary purpose is to store a set of fields or properties. You can
base your definition of value equality on a comparison of all the
fields and properties in the type, or you can base the definition on a
subset.

Related

Record types: overriding EqualityContract breaks the equality/hashcode match

Newly introduced record types allow to override EqualityContract for type which makes possible to create a situation when two objects are equal but have different hashcodes which opposes guidelines for GetHashCode overriding:
If you override the GetHashCode method, you should also override Equals, and vice versa. If your overridden Equals method returns true when two objects are tested for equality, your overridden GetHashCode method must return the same value for the two objects.
public record Base(string Foo);
public record Child(string Foo, string Bar) : Base(Foo)
{
protected override Type EqualityContract => typeof(Base);
}
var b = new Base("Foo");
var c = new Child("Foo", "Bar");
Console.WriteLine(b == c); // True
Console.WriteLine(b.GetHashCode() == c.GetHashCode()); // False
While removing the extra property from Child makes GetHashCode and Equals "match".
Obviously this can be fixed with overriding GetHashCode, but I wonder why overriding EqualityContract does not automatically lead to having GetHashCode return value "matching" Equals implementation? Or is there any other way to handle that except manual GetHashCode override?
As you can see in equality members part of records proposal,
GetHashCode() returns an int result of a deterministic function
combining the following values:
For each instance field fieldN in the record type that is not inherited, the value of
System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)
where TN is the field type, and
If there is a base record type, the value of base.GetHashCode(); otherwise the value of
System.Collections.Generic.EqualityComparer<System.Type>.Default.GetHashCode(EqualityContract).
So, in your example GetHashCode for Base will be
public override int GetHashCode()
{
return EqualityComparer<Type>.Default.GetHashCode(EqualityContract) + EqualityComparer<string>.Default.GetHashCode(Foo);
}
And for the Child
public override int GetHashCode()
{
return base.GetHashCode() + EqualityComparer<string>.Default.GetHashCode(Bar);
}
For the inherited record the EqualityContract isn't used for hash code calculation. If an extra property Bar is removed, the value from Base is used and you'll get a hash values equality. So, overriding of GetHashCode is needed.
This behavior is also observed using sharplab.io

EqualityComparer<T>.Default doesn't return the derived EqualityComparer

I have a class Person, and created an equality comperer class derived from EqualityComparer < Person >. Yet the default EqualityComparer doesn't call the Equals function of my equality comparer
According to MSDN EqualityComparer < T > .Default property:
The Default property checks whether type T implements the System.IEquatable interface and, if so, returns an EqualityComparer that uses that implementation. Otherwise, it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T.
In the (simplified) example below, class Person does not implement implement System.IEquatable < Person >. So I'd expect that PersonComparer.Default would return an instance of PersonComparer.
Yet PersonComparer.Equals is not called. There is no debug output and the returned value is false.
public class Person
{
public string Name { get; set; }
}
public class PersonComparer : EqualityComparer<Person>
{
public override bool Equals(Person x, Person y)
{
Debug.WriteLine("PersonComparer.Equals called");
return true;
}
public override int GetHashCode(Person obj)
{
Debug.WriteLine("PersonComparer.GetHasCode called");
return obj.Name.GetHashCode();
}
}
public static void Main()
{
Person x = new Person() { Name = "x" };
Person y = new Person() { Name = "x" };
bool b1 = PersonComparer.Default.Equals(x, y);
}
Question: What am I doing wrong?
In case you might wonder why I don't want to implement IEquatable < Person >.
My problem is comparable with the comparison of strings. Sometimes you want two strings to be equal if they are exactly the same strings, sometimes you want to ignore case, and sometimes you want to treat characters as óò etc all as if they are the character o.
In my case: I store a Person in something, which might be a database, but it might as well be a File or a MemoryStream. Upon return I get an identifier, which in case of a database is of course the primary key. With this key I am able to retrieve an object with the same values.
I want to test this in a unit Test: I you put something in it, you should get a key that can be used to retrieve the item. Alas, the database doesn't return the same Person, but a derived class of Person (At least when using EF 6). So I can't use the normal IEquatable, which should return false if the objects are not of the same type. That's why I wanted to use a special comparer, one that declares two Persons equal if they have the same values for the properties, even if they are both different derived classes from Person. Very comparable as a string comparer that accepts O and o and ó to be equal
Let's re-read the quote you added:
The Default property checks whether type T implements the System.IEquatable interface and, if so, returns an EqualityComparer
that uses that implementation.
So, the Default property looks for an implementation of IEqutable<T>, which your Person does not provide.
If the object doesn't implement IEquatable<T>, then:
Otherwise, it returns an EqualityComparer that uses the overrides of Object.Equals and Object.GetHashCode provided by T.
Which shows you exactly why object.Equals and object.GetHashCode are the ones being called. You have two choices, either use new PersonComparer().Equals(), or implement IEquatable<Person> on your type (if such a single implementation is possible).
That is because the Default property of EqualityComparer<T> does not return a PersonComparer, but a ObjectEqualityComparer<T>. And that ObjectEqualityComparer<T>, as you referenced the documentation, compares using the Equals on Person.
See the actual source. At line 89 it returns the ObjectEqualityComparer<T>.
There is actually nothing wrong with your code, as you can see when you actually try to run your code on an instance of PersonComparer:
bool b1 = new PersonComparer().Equals(x, y);
You have mixed up some things, but it's not surprising since, everyone must admit that the .NET Framework has a bit too many possibilities for equality comparison.
You should implement the IEqualityComparer<T> only if you want to specify special comparison logic for specific situations, such as to a Dictionary<TKey, TValue>, for example.
The EqualityComparer<T> is confusingly an overridable type in .NET; however, it is not intended that you override it, and there's no use in doing so. It provides a default comparer for generic types and it will call your IEquatable<T> implementation if you use T in a List<T> (Contains, IndexOf, etc.) or when T is a key of a dictionary and you didn't pass any custom IEqualityComparer to the dictionary.

Which IEqualityComparer is used in a Dictionary?

Lets say I instantiate a dictionary like this
var dictionary = new Dictionary<MyClass, SomeValue>();
And MyClass is my own class that implements an IEqualityComparer<>.
Now, when I do operations on the dictionary - such as Add, Contains, TryGetValue etc - does dictionary use the default EqualityComparer<T>.Default since I never passed one into the constructor or does it use the IEqualityComparer that MyClass implements?
Thanks
It will use the default equality comparer.
If an object is capable of comparing itself for equality with other objects then it should implement IEquatable, not IEqualityComparer. If a type implements IEquatable then that will be used as the implementation of EqualityCOmparer.Default, followed by the object.Equals and object.GetHashCode methods otherwise.
An IEqualityComparer is designed to compare other objects for equality, not itself.
It will use IEqualityComparer<T>.Default if you don't specify any equality comparer explicitly.
This default equality comparer will use the methods Equals and GetHashCode of your class.
Your key class should not implement IEqualityComparer, this interface should be implemented when you want to delegate equality comparisons to a different class. When you want the class itself to handle equality comparisons, just override Equals and GetHashCode (you can also implement IEquatable<T> but this is not strictly required).
If you want to use IEquatable<T> you can do so without having to create a separate class but you do need to implement GetHashCode().
It will pair up GetHashCode() and bool Equals(T other) and you don't have to use the archaic Equals signature.
// tested with Dictionary<T>
public class Animal : IEquatable<Animal>
{
public override int GetHashCode()
{
return (species + breed).GetHashCode();
}
public bool Equals(Animal other)
{
return other != null &&
(
this.species == other.species &&
this.breed == other.breed &&
this.color == other.color
);
}
}

What is the proper way to implement Equation functions [duplicate]

I'm having some difficulty using Linq's .Except() method when comparing two collections of a custom object.
I've derived my class from Object and implemented overrides for Equals(), GetHashCode(), and the operators == and !=. I've also created a CompareTo() method.
In my two collections, as a debugging experiment, I took the first item from each list (which is a duplicate) and compared them as follows:
itemListA[0].Equals(itemListB[0]); // true
itemListA[0] == itemListB[0]; // true
itemListA[0].CompareTo(itemListB[0]); // 0
In all three cases, the result is as I wanted. However, when I use Linq's Except() method, the duplicate items are not removed:
List<myObject> newList = itemListA.Except(itemListB).ToList();
Learning about how Linq does comparisons, I've discovered various (conflicting?) methods that say I need to inherit from IEquatable<T> or IEqualityComparer<T> etc.
I'm confused because when I inherit from, for example, IEquatable<T>, I am required to provide a new Equals() method with a different signature from what I've already overridden. Do I need to have two such methods with different signatures, or should I no longer derive my class from Object?
My object definition (simplified) looks like this:
public class MyObject : Object
{
public string Name {get; set;}
public DateTime LastUpdate {get; set;}
public int CompareTo(MyObject other)
{
// ...
}
public override bool Equals(object obj)
{
// allows some tolerance on LastUpdate
}
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + Name.GetHashCode();
hash = hash * 23 + LastUpdate.GetHashCode();
return hash;
}
}
// Overrides for operators
}
I noticed that when I inherit from IEquatable<T> I can do so using IEquatable<MyObject> or IEquatable<object>; the requirements for the Equals() signature change when I use one or the other. What is the recommended way?
What I am trying to accomplish:
I want to be able to use Linq (Distinct/Except) as well as the standard equality operators (== and !=) without duplicating code. The comparison should allow two objects to be considered equal if their name is identical and the LastUpdate property is within a number of seconds (user-specified) tolerance.
Edit:
Showing GetHashCode() code.
It doesn't matter whether you override object.Equals and object.GetHashCode, implement IEquatable, or provide an IEqualityComparer. All of them can work, just in slightly different ways.
1) Overriding Equals and GetHashCode from object:
This is the base case, in a sense. It will generally work, assuming you're in a position to edit the type to ensure that the implementation of the two methods are as desired. There's nothing wrong with doing just this in many cases.
2) Implementing IEquatable
The key point here is that you can (and should) implement IEquatable<YourTypeHere>. The key difference between this and #1 is that you have strong typing for the Equals method, rather than just having it use object. This is both better for convenience to the programmer (added type safety) and also means that any value types won't be boxed, so this can improve performance for custom structs. If you do this you should pretty much always do it in addition to #1, not instead of. Having the Equals method here differ in functionality from object.Equals would be...bad. Don't do that.
3) Implementing IEqualityComparer
This is entirely different from the first two. The idea here is that the object isn't getting it's own hash code, or seeing if it's equal to something else. The point of this approach is that an object doesn't know how to properly get it's hash or see if it's equal to something else. Perhaps it's because you don't control the code of the type (i.e. a 3rd party library) and they didn't bother to override the behavior, or perhaps they did override it but you just want your own unique definition of "equality" in this particular context.
In this case you create an entirely separate "comparer" object that takes in two different objects and informs you of whether they are equal or not, or what the hash code of one object is. When using this solution it doesn't matter what the Equals or GetHashCode methods do in the type itself, you won't use it.
Note that all of this is entirely unrelated from the == operator, which is its own beast.
The basic pattern I use for equality in an object is the following. Note that only 2 methods have actual logic specific to the object. The rest is just boiler plate code that feeds into these 2 methods
class MyObject : IEquatable<MyObject> {
public bool Equals(MyObject other) {
if (Object.ReferenceEquals(other, null)) {
return false;
}
// Actual equality logic here
}
public override int GetHashCode() {
// Actual Hashcode logic here
}
public override bool Equals(Object obj) {
return Equals(obj as MyObject);
}
public static bool operator==(MyObject left, MyObject right) {
if (Object.ReferenceEquals(left, null)) {
return Object.ReferenceEquals(right, null);
}
return left.Equals(right);
}
public static bool operator!=(MyObject left, MyObject right) {
return !(left == right);
}
}
If you follow this pattern there is really no need to provide a custom IEqualityComparer<MyObject>. The EqualityComparer<MyObject>.Default will be enough as it will rely on IEquatable<MyObject> in order to perform equality checks
You cannot "allow some tolerance on LastUpdate" and then use a GetHashCode() implementation that uses the strict value of LastUpdate!
Suppose the this instance has LastUpdate at 23:13:13.933, and the obj instance has 23:13:13.932. Then these two might compare equal with your tolerance idea. But if so, their hash codes must be the same number. But that will not happen unless you're extremely extremely lucky, for the DateTime.GetHashCode() should not give the same hash for these two times.
Besides, your Equals method most be a transitive relation mathematically. And "approximately equal to" cannot be made transitive. Its transitive closure is the trivial relation that identifies everything.

Why do we need GetHashCode() function in the Object Model Project? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why is it important to override GetHashCode when Equals method is overriden in C#?
I was looking into the following class in my Object Model and could not understand the significance of adding GetHashCode() in the Class.
Sample Class
public class SampleClass
{
public int ID { get; set; }
public String Name { get; set; }
public String SSN_Number { get; set; }
public override bool Equals(Object obj)
{
if (obj == null || GetType() != obj.GetType())
return false;
SampleClass cls = (SampleClass)obj;
return (ID == cls.ID) &&
(Name == cls.Name) &&
(SSN_Number == cls.SSN_Number);
}
public override int GetHashCode()
{
return ID.GetHashCode() ^ Name.GetHashCode() ^ SSN_Number.GetHashCode();
}
}
Suppose I have a list of Sample Class Object and I want to get a specific index. Then Equals() can help me to get that record. Why should I use GetHashCode() ?
You need to handle both, because GetHashCode() is used by many collection implementations (like Dictionary) in concert with the Equals method. The important thing is that if you override the implementation of Equals, then you must override GetHashCode in such a way that any two objects that are Equal according to your new implementation also must return an identical Hash Code.
If they don't, then they will not work in Dictionary's properly. It's generally not that hard. One way that I often times do this is by taking the Properties of an object that I use for equality, and joining them together in a String object, and then return String.GetHashCode.
String has a pretty good implementation of GetHashCode that returns a wide range of integers for various values that make for good spreads in a sparse collection.
It is necessary to provide an override to GetHashCode, when your custom class overrides Equals. If you omit GetHashCode, you will get a compiler warning saying "A public type overrides System.Object.Equals but does not override System.Object.GetHashCode".
GetHashCode returns a value based on the current instance that is suited for hashing algorithms and data structures such as a hash table. Two objects that are the same type and are equal must return the same hash code to ensure that instances of System.Collections.HashTable and System.Collections.Generic.Dictionary<TKey, TValue> work correctly.
Suppose it was not necessary to override the GetHashCode in your custom class, the hash based collections would have to then use the base class' Object.GetHashCode which might not give correct results for all instances of your custom class.
If you observe the code you have posted, your Equals method compares
ID, Name and SSN for the 2 instances to return equality result
and the same attributes are being used for the hashing algorithm
(ID^Name^SSN) inside your GetHashCode method.

Categories