Overloading just equality operators is not enough. Under different circumstances, all of the following can be called:
object.Equals and object.GetHashCodeIEquatable<T>.Equals (optional, allows avoiding boxing)operator == and operator != (optional, allows using operators)When overriding Equals, GetHashCode must also be overriden. When implementing Equals, there are many special cases: comparing to objects of a different type, comparing to self etc.
When NOT overridden Equals method and == operator behave differently for classes and structs. For classes just references are compared, and for structs values of properties are compared via reflection what can negatively affect performance. == can not be used for comparing structs unless it is overridden.
Generally equality operation must obey the following rules:
A always equals A (may not be true for NULL values in some systems).A equals B, and B equals C, then A equals C.A equals B, then A and B have equal hash codes.B and C are instances of Class2 inherited from Class1:
Class1.Equals(A,B) must always return the same value as the call to Class2.Equals(A,B).class Student : IEquatable<Student>
{
public string Name { get; set; } = "";
public bool Equals(Student other)
{
if (ReferenceEquals(other, null)) return false;
if (ReferenceEquals(other, this)) return true;
return string.Equals(Name, other.Name);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
return Equals(obj as Student);
}
public override int GetHashCode()
{
return Name?.GetHashCode() ?? 0;
}
public static bool operator ==(Student left, Student right)
{
return Equals(left, right);
}
public static bool operator !=(Student left, Student right)
{
return !Equals(left, right);
}
}