使用IComparable.不使用幻数进行比较

本文关键字:比较 IComparable 使用 | 更新日期: 2023-09-27 18:20:48

我真的很讨厌与IComparer合作——在与.Net合作多年后,直到今天,我仍然经常被那些1和-1弄糊涂。

我是否可以用一些不言自明的名称替换Compare结果值,而不必在每次Compare调用后将输出整数强制转换为其他值?

我试图定义这样一个枚举:

public enum ComparerResult
{
    ALessThanB = -1,
    Equal = 0,
    AGreaterThanB = 1
}
if(comparer.Compare(a, b) == ComparerResult.ALessThanB)

但是,如果没有强制转换,它当然不会编译。

这当然也适用于IComparableCompareTo.

感谢您的想法

使用IComparable.不使用幻数进行比较

我更喜欢用这个来表示小于:

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

这是一个很好的助记符,因为在两个操作数之间使用相同的运算符与零进行比较。


正如Reddog在评论中提醒我的那样,接口规范并不特别要求-1和1;它只需要消极和积极的结果。因此,不能保证您当前使用的逻辑在所有情况下都能工作。

只创建常量怎么样?这样就不必从枚举中进行强制转换。

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

IComparableIComparer上的扩展方法怎么样?

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;
    }
}

使用常量是危险的。IComparer.Compare的文档仅指定如果x < y,返回值应为"小于零",如果x > y,返回值则应为"大于零"。因此,您不应该假设返回值是[-1,0,1]之一。

相反,我建议在IComparer上创建一个扩展方法,为您做这项工作。

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;
}