Search code examples
c#.neticomparableiequatable

How to implement Multi-type IComparable / IEquatable in C#


Let say I have the following class:

public sealed class ScaleValue : 
    IComparable, IComparable<ScaleValue>, IEquatable<ScaleValue>
{
    public double Value
    { get; set;}
    public string Definition
    { get; set;}

    // interface methods
    ...
}

If I want to make my class comparable to a double should I just include IComparable<double> and implement it that way or do I have to do it another way?

And when I want my class to be comparable to doubles should the double.CompareTo give the same result as the ScaleValue.CompareTo?

and how about Equals?

I think I put the responsibilities wrong in my design. I think my best option is to make a Scale class with a ContainsValue(double Value) method. This way I can look up the value and keep the responsibilities where they are needed.


Solution

  • What your class is comparable to is up to you. You could make it comparable to anything, as the non-generic version of the IComparable interface takes an object; in the implementation of CompareTo method, you can basically sniff the type of the object (unless it is null).

    When you use the generic version of IComparable<T>, you're making the statement that you implement a strongly-typed comparison method to whatever the type parameter T is.

    Generally, if you have an IComparable<T> implementation for one type, you probably should have an IEquatable<T> implementation as well.

    Having an IComparable/IComparable<T> implementation means that what is being represented by the structure has a natural ordering to it. Ordering also implies that there can be equality between two instances: if instance a of T is not greater than or less than instance b of T then it must be equal.

    To that end, if you implement IComparable/IComparable<T>, then logic dictates that you implement IEquatable/IEquatable<T>.

    Of course, when you implement IEquatable/IEquatable<T>, you should override Equals and GetHashCode.

    Which in turn means that you should override all the comparison operators:

    • == (which implies !=)
    • < and <=
    • > and >=