All of the resources showing how to override Equals(object) and GetHashCode() use numeric fields to implement the GetHashCode() method:
Implementing the Equals Method
What's the best strategy for Equals and GetHashCode?
Why is it important to override GetHashCode when Equals method is overridden?
However, in my class, I do not have any numeric fields. It is a node in a tree with a reference to its parent, children, and an interface as the data:
public class Node
{
private IInterface myInterface;
private Node parent;
private List<Node> children = new List<Node>();
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var node = (Node)obj;
return myInterface == node.myInterface;
}
public override int GetHashCode()
{
???
}
}
What should I set the hashcode with?
According to Equals implementation, two Nodes instances are equal if and only if their myInterface are equal:
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var node = (Node)obj;
// instances are equal if and only if myInterface's are equal
return myInterface == node.myInterface;
}
That's why myInterface is the only source for GetHashCode:
public override int GetHashCode()
{
return null == myInterface ? 0 : myInterface.GetHashCode();
}
P.S. (Edited, thanks to Kris Vandermotten) Often, it's a good practice to check for ReferenceEquals in the Equals implementation before comparing potentially time/resource consuming myInterfaces:
public override bool Equals(object obj) {
// Easy tests:
// 1. If "this" and "obj" are in fact just the same reference?
// 2. Since `Node` (or Equals) is not sealed, the safiest is to check types
if (object.ReferenceEquals(this, obj))
return true;
else if (null == obj || other.GetType() != GetType())
return false;
// Potentially time/resource cosuming (we don't know IInterface implementation)
return ((Node) obj).myInterface == myInterface;
}
Related
Given a parent record type:
public record Foo(string Value);
And two record sub-classes Bar and Bee I wonder if it is possible to implement Equals in the base class so as instances of Foo, Bar or Bee are all considered equal based on Value (both with Equals and ==).
I tried the following after digesting https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/records, but it didn't quite work:
public record Foo(string Value)
{
public virtual bool Equals(Foo? other)
{
return other != null && this.Value == other.Value;
}
public override int GetHashCode() => this.Value.GetHashCode();
}
public record Bar(string Value) : Foo(Value)
{
protected override Type EqualityContract => typeof(Foo);
}
public record Bee(string Value) : Foo(Value)
{
protected override Type EqualityContract => typeof(Foo);
}
[Test]
public void TestFooBar()
{
Assert.That(new Foo("foo") == new Bar("foo"), Is.True); // Passes
Assert.That(new Bar("foo") == new Foo("foo"), Is.True); // Fails!
}
[Test]
public void TestFooBee()
{
Assert.That(new Foo("foo") == new Bee("foo"), Is.True); // Passes
Assert.That(new Bee("foo") == new Foo("foo"), Is.True); // Fails!
}
[Test]
public void TestBarBee()
{
Assert.That(new Bar("foo") == new Bee("foo"), Is.True); // Fails!
Assert.That(new Bee("foo") == new Bar("foo"), Is.True); // Fails!
}
This question is specific to record types. I don't need an example with classes (I know that already).
When I look at sharplab.io, I see the following implementation for Bar:
[System.Runtime.CompilerServices.NullableContext(2)]
public override bool Equals(object obj)
{
return Equals(obj as Bar);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public sealed override bool Equals(Foo other)
{
return Equals((object)other);
}
And in Foo:
[System.Runtime.CompilerServices.NullableContext(2)]
public static bool operator ==(Foo left, Foo right)
{
if ((object)left != right)
{
if ((object)left != null)
{
return left.Equals(right);
}
return false;
}
return true;
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override bool Equals(object obj)
{
return Equals(obj as Foo);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public virtual bool Equals(Foo other)
{
if (other != null)
{
return Value == other.Value;
}
return false;
}
So naturally new Bar("foo") == new Bee("foo") would end-up calling Bar.Equals(Foo?), which is synthetic and relies on Bar.Equals(object) which will cast to Bar or return null, and because a Bee is not a Bar it ends-up comparing null.
It doesn't seem possible to override some of the synthetic Equals methods so it seems I cannot escape this behavior.
Or, can I?
NOTE: I'm on .NET SDK 6.0.
This is the stack trace when calling new Bar("foo") == new Foo("foo"):
at Foo.Equals(Foo other)
at Bar.Equals(Bar other)
at Bar.Equals(Object obj)
at Bar.Equals(Foo other)
at Foo.op_Equality(Foo r1, Foo r2)
According to the draft spec, you cannot declare any of those methods explicitly (i.e. do not have control over them) except Foo.Equals(Foo) and Bar.Equals(Bar), at which point other has already been (unsuccessfully) casted to Bar, in Bar.Equals(Object).
Though it is not totally impossible - you can declare the operators ==(Bar, Foo), !=(Bar, Foo) etc manually, and let operator overload resolution pick your operator, instead of the ==(Foo, Foo) one, which you have no control over. But this is quite tedious to do for all the types, and you'd still have the problem of Bar.Equals(Foo) not working the way you want. :(
EqualityContract is rather irrelevant. It is only checked in the generated Foo.Equals(Foo),
The synthesized Equals(R?) returns true if and only if each of the following are true:
[...]
If there is a base record type, the value of base.Equals(other) (a non-virtual call to public virtual bool Equals(Base? other)); otherwise the value of EqualityContract == other.EqualityContract.
but at that point other is null already! Not to mention that you wrote your own Foo.Equals(Foo), so the EqualityContracts are not used at all.
I have a class A, which holds a string property and overwrites Equals for equality testing.
public class A
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public override bool Equals(object obj)
{
return obj is A arg && (Prop == arg.Prop);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
I also have a class B which has a List<A> as property:
public class B
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
I wanna be able to compare to instances of B for equality and order.
How can I write the Equals method in B by not rewriting the same code I wrote in A?
Is there a way to reuse the A Equals?
Update: My first version assumed B is derived from A.
A.Equals:
If A is not sealed, obj is A ... can return a false positive if different types are compared. So the corrected version:
public override bool Equals(object obj)
{
return obj is A other
&& this.Prop == other.Prop
&& this.GetType() == other.GetType(); // not needed if A is sealed
}
A.GetHashCode:
base.GetHashCode will return different hash codes for different but equal instances, which is wrong. Derive the hashcode from self properties instead. If Prop acts like some ID, then simply return Prop.GetHashCode()
B.Equals:
public override bool Equals(object obj)
{
return obj is B other
&& this.Prop.SequenceEqual(other.Prop) // will re-use A.Equals
&& this.Prop.GetType() == other.Prop.GetType() // not needed if different IReadOnlyList types are ok
&& this.GetType() == other.GetType(); // not needed if B is sealed
}
B.GetHashCode:
You can aggregate the hash codes of A instances. Here I use a simple XOR but if the same items can often come in a different order you can come up with something more fancy.
return Prop.Aggregate(0, (h, i) => h ^ i.GetHashCode());
Implementing Equals for a list can be done by using the SequenceEquals method (from System.Linq namespace), which ensures that each item in one list equals the item at the same index in the other list.
One thing you might consider changing, however is your implementation of GetHashCode. This method should return the same number if two items are equal (though it's not guaranteed that two items with the same hash code are equal). Using base.GetHashCode() does not meet this requirement, since the base is object in this case; according to the documentation, "hash codes for reference types are computed by calling the Object.GetHashCode method of the base class, which computes a hash code based on an object's reference", so objects only return the same HashCode if they refer to the exact same object.
The HashCode should be based on the same properties used to determine equality, so in this case we want to use Prop.GetHashCode() for class A, and we want to aggregate the hashcode for all the items in Prop for class B.
Here's one way the classes could be refactored:
public class A : IEquatable<A>
{
public string Prop { get; }
public A(string val)
{
Prop = val;
}
public bool Equals(A other)
{
if (other == null) return false;
return Prop == other.Prop;
}
public override bool Equals(object obj)
{
return Equals(obj as A);
}
public override int GetHashCode()
{
return Prop.GetHashCode();
}
}
public class B : IEquatable<B>
{
public IReadOnlyList<A> Prop { get; }
public B(IReadOnlyList<A> val)
{
Prop = val;
}
public bool Equals(B other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
if (Prop == null) return other.Prop == null;
return other.Prop != null && Prop.SequenceEqual(other.Prop);
}
public override bool Equals(object obj)
{
return Equals(obj as B);
}
public override int GetHashCode()
{
return Prop?.Aggregate(17,
(current, item) => current * 17 + item?.GetHashCode() ?? 0)
?? 0;
}
}
Linq contains a useful method to compare collections: SequenceEqual
public override bool Equals(object obj)
{
if (!(obj is B other))
{
return false;
}
if (this.Prop == null || other.Prop == null)
{
return false;
}
return this.Prop.SequenceEqual(other.Prop);
}
Also, implement IEquatable<T> when you override Equals.
How about something like this:
public override bool Equals(object obj)
{
if(!(obj is B))
{
return false;
}
var b = obj as B;
if(b.Prop.Count != this.Prop.Count)
{
return false;
}
for(var i =0; i < Prop.Count; i++)
{
if (!Prop.ElementAt(i).Equals(b.Prop.ElementAt(i)))
{
return false;
}
}
return true;
}
I'm programming in C# Unity and have really annoying problem - I want to define special Pair class with following relations:
public class Pair<T1>{
public int First;
public T1 Second;
public bool Equals(Pair<T1> b){
return First == b.First;
}
public static bool operator==(Pair<T1> a, Pair<T1> b){
return a.First == b.First;
}
public static bool operator!=(Pair<T1> a, Pair<T1> b){
return a.First != b.First;
}
}
Which gives me following warning:
Warning CS0660: 'Pair' defines operator == or operator != but does
not override Object.Equals(object o) (CS0660) (Assembly-CSharp)
But also when I spawn two objects of Pair type with same First integer, their == operator returns True (as I want). When I only declare Equals function, same == operator returns False value (I understand that somehow Unity compares their addressees in memory), with no warnings. Is there any method to avoid warnings and still get True value of == operator?
Just override that method to make the compiler happy :
public override bool Equals(object o)
{
if(o == null)
return false;
var second = o as Pair<T1>;
return second != null && First == second.First;
}
public override int GetHashCode()
{
return First;
}
The method you created is a custom equals method, you need to override that of the object class (which is used in the == && != operators)
You need to override the Equal:
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Pair<T1>) obj);
}
And the GetHashCode method:
public override int GetHashCode()
{
unchecked
{
return (First*397) ^ EqualityComparer<T1>.Default.GetHashCode(Second);
}
}
This is a project question that i just cant seem to answer
using System;
namespace ConsoleApplication2
{
internal class Equipment : IComparable
{
private readonly string type;
private readonly int serialNo;
private string colour;
public decimal cost;
public Equipment(string type, int serialNo)
{
this.type = type == null ? "" : type.Trim();
this.serialNo = serialNo;
}
public string Key
{
get { return type + ":" + serialNo; }
}
int IComparable.CompareTo(object obj)
{
return 0;
}
}
}
(a) Override the appropriate method o ensure that different instances of the class that represent the same equipment item will be considered the same in the system.
(b) Override the appropriate method to enable instances of this class to be stored (and found) by key in a hash table
You should override the Equals and GetHashCode methods for this purpose.
Override Equals() with an appropriate logic of comparision
Override GetHashCode(), see GetHashCode Guidelines in C#
You must start reading this before doing such a task
Why is it important to override GetHashCode when Equals method is overriden in C#?
Writing GetHashCode manually is not that easy. Anyhow, that's code generated for this purpose by ReSharper. It's a complete solution. (It should be contained within your class definition of course). But what would you say, if you were asked - why and how it works? It might be embarassing.
So, apart from GetHashCode and Equals, which others have suggested you reading about, you might also look up http://msdn.microsoft.com/en-us/library/system.object.referenceequals.aspx as well as http://msdn.microsoft.com/en-us/library/a569z7k8(v=VS.100).aspx
As for the mystery behind 397 in GetHashCode, have a look at this question here on StackOverflow: Why is '397' used for ReSharper GetHashCode override?
public bool Equals(Equipment other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Equals(other.colour, colour) && other.cost == cost && other.serialNo == serialNo && Equals(other.type, type);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != typeof (Equipment))
{
return false;
}
return Equals((Equipment) obj);
}
// note: if "Override the appropriate method to enable instances of this class
// to be stored (and found) by key in a hash table" is supposed to mean that only type and
// serialNo should be taken into account (since they are used to generate
// the Key value) - just remove the lines with cost and colour
public override int GetHashCode()
{
unchecked
{
int result = (colour != null ? colour.GetHashCode() : 0);
result = (result*397) ^ cost.GetHashCode();
result = (result*397) ^ serialNo;
result = (result*397) ^ (type != null ? type.GetHashCode() : 0);
return result;
}
}
I've wondered about this, so I figure I'll ask it.
Most places you'll see use the same semantic logic for overriding Equals as GetHashCode for memberwise equality...however they usually use different implementations:
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var other = (MyType)obj;
if (other.Prop1 != Prop1)
{
return false;
}
return true;
}
public override int GetHashCode()
{
int hash = -657803396;
num ^= Prop1.GetHashCode();
return num;
}
If you're implementing memberwise equality for your type (lets say for storing in a dictionary), why not just override GetHashCode then do something like this for Equals:
public override bool Equals(object obj)
{
return this.HashEqualsAndIsSameType(obj);
}
public static bool HashEquals(this object source, object obj)
{
if (source != null && obj != null)
{
return source.GetHashCode() == obj.GetHashCode();
}
if (source != null || obj != null)
{
return false;
}
return true;
}
public static bool HashEqualsAndIsSameType<T>(this T source, object obj)
{
return (obj == null || obj.GetType() == typeof(T)) && source.HashEquals(obj);
}
Because there is a real risk of conflicts. Hash-codes are not unique. They can (when different) prove inequality, but never equality. When looking for an item:
get the hash-code(s)
if the hash-code is different, the object is different; discard it
if the hash-code is the same, check Equals:
if Equals reports true they are the same
else discard
Consider long... since hash-code is int, it is easy to see that there are lots and lots of conflicts.
Hashes are not 1-to-1, you can have multiple different values that hash to the same value, but which should compare as not equal. So you cannot really implement Equals in terms of GetHashCode. This is why you have collisions in a hash table, and why a hash table lookup must involve call(s) to both GetHashCode and Equals.