Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IComparable and Equals()

Tags:

c#

From MSDN

Types that implement IComparable must override Equals.Types that override Equals must also override GetHashCode; otherwise, Hashtable might not work correctly.

I didn't quite get it. Can anyone explain.

like image 307
softwarematter Avatar asked Feb 03 '23 09:02

softwarematter


1 Answers

IComparable is an interface that defines that two instances of the implementing class can be seen as greater than, less than or equal to one another. Since you have defined equality in the methods of that interface you also need to override the Equals method (and equality operator) to ensure the results from the two are consistent.

public class EqualityTest : IComparable<EqualityTest>
{
      public int Value { get; set; }

      public int CompareTo(EqualityTest other)
      {
           return this.Value.CompareTo(other.Value);
      }
}

In the above example I have implemented IComparable, but not overridden Equals. If you call CompareTo with two separate instances of the class that have the same Value it will say there are equal. If you call Equals with the same two instances it will say they are not equal as it will test to see if they are the same object (the default implementation of Equals).

Two equal items should return the same hash code (which are used for quickly finding items used as keys in hash tables) so if you override Equals then you should also override GetHashCode()


As an example I just created the following class in my IDE:

public class EqualityTest
{
     public string A { get; set; }
     public string B { get; set; }
}

And ran Resharper's helpful "Generate Equality" function saying that I wanted both A and B to affect equality. This is the code it created:

    public bool Equals(EqualityTest other)
    {
        if (ReferenceEquals(null, other))
        {
            return false;
        }

        if (ReferenceEquals(this, other))
        {
            return true;
        }

        return Equals(other.A, A) && Equals(other.B, B);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }

        if (ReferenceEquals(this, obj))
        {
            return true;
        }

        if (obj.GetType() != typeof(EqualityTest))
        {
            return false;
        }

        return Equals((EqualityTest)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return ((A != null ? A.GetHashCode() : 0)*397) ^ (B != null ? B.GetHashCode() : 0);
        }
    }

    public static bool operator ==(EqualityTest left, EqualityTest right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(EqualityTest left, EqualityTest right)
    {
        return !Equals(left, right);
    }

So if you are overriding Equals then you should also define all of the above to ensure consistency, if you are implementing IComparable then the same applies.

like image 141
Martin Harris Avatar answered Feb 15 '23 13:02

Martin Harris