Question

I really hate working with IComparer - to this day, after years of working with .Net, I still get regularly confused by those 1s and -1s.

Can I somehow replace the Compare result values with some self-explanatory names without having to cast the output integers to something else after every Compare call?

I tried to define an enum like this:

public enum ComparerResult
{
    ALessThanB = -1,
    Equal = 0,
    AGreaterThanB = 1
}

if(comparer.Compare(a, b) == ComparerResult.ALessThanB)

But that of course won't compile without a cast.

This of course also applies to IComparable.CompareTo.

Thanks for your ideas

Was it helpful?

Solution

I prefer this to express less-than:

if (comparer.Compare(a, b) < 0)

This is a nice mnemonic because you use the same operator for comparison with zero as you would between the two operands.


As Reddog reminded me in the comments, the specification for the interfaces does not require -1 and 1 specifically; it only requires negative and positive results. As such, the logic you're currently using is not guaranteed to work in all cases.

OTHER TIPS

How about just creating constants? That way you won't have to cast from an enum.

public class CompareHelper
{
    public const int ALessThanB = -1;
    public const int Equal = 0;
    public const int AGreaterThanB = 1;
}

What about an extension method on IComparable and IComparer ?

public static class IComparableExtension
{
    public static ComparerResult NiceCompareTo(this IComparable a, IComparable b)
    {
        int result = a.CompareTo(b);
        if (result > 0) return ComparerResult.ALessThanB;
        if (result < 0) return ComparerResult.AGreaterThanB;
        return ComparerResult.Equal;
    }
}

public static class IComparerExtension
{
    public static ComparerResult NiceCompare(this IComparer c, IComparable a, IComparable b)
    {
        int result = c.Compare(a, b);
        if (result > 0) return ComparerResult.ALessThanB;
        if (result < 0) return ComparerResult.AGreaterThanB;
        return ComparerResult.Equal;
    }
}

Using constants is dangerous. The documentation for IComparer.Compare only specifies that the return value should be "less than zero" if x < y, or "greater than zero" if x > y. So you should not assume that the return value will be one of [-1, 0, 1].

What I would suggest instead is creating an extension method on IComparer that does the work for you.

static MyCompare(this IComparable self, object x, object y)
{
    var result = self.Compare(x, y);
    if(result < 0) return ComparerResult.ALessthanB;
    if(result == 0) return ComparerResult.Equal;
    return ComparerResult.AGreaterThanB;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top