比较实现IComparable的项目的问题

Ram*_*Vel 5 c# generics icomparable

我正在研究一种扩展方法,它通过特定的选择器找到最小项目.代码下方

    public static T MinBy<T, K>(this IEnumerable<T> src, Func<T, K> selector) where K : struct, IComparable, IConvertible
    {
        var min = default(K);
        T minItem = default(T);
        foreach (var item in src)
        {
            var current = selector(item);
            if (current < min)
            {
                min = current;
                minItem = item;
            }
        }

        return minItem;

    }
Run Code Online (Sandbox Code Playgroud)

它给出了错误Error Operator '<' cannot be applied to operands of type 'K' and 'K'.但我已经指定了通用约束K应该是Struct and IComparable.我相信所有数字数据类型都可以满足于此.

那为什么这是一个无效的操作.

Jon*_*eet 18

IComparable没有(也不能)说出关于运营商的任何事情.你应该使用:

if (current.CompareTo(min) < 0)
Run Code Online (Sandbox Code Playgroud)

运算符是静态的,只是过而不是重载.您不能在接口中要求运算符,并且方法的存在不会神奇地改变运算符将执行的操作.(例如,覆盖Equals不会改变==行为方式.)

您还应该注意,由于您的约束仅涉及非泛型IComparable接口,因此您将在每次操作时进行装箱.我建议你改变约束IComparable<K>.(或者删除约束,然后Comparer<K>.Default像Marc建议的那样使用.)

关于您的方法的其他一些评论:

  • 如果所有键值都超过默认值K(例如K = int且所有键都为正),那么您将找不到项目
  • 您可能希望有一个接受特定的重载IComparare<K>(但只有在您删除了类似的约束时)
  • 没有必要约束K到值类型.如果我想找到具有词典最早名称的人,该怎么办?
  • 如果没有元素,它将返回默认值T; 为了适应LINQ的其余部分,我建议投掷InvalidOperationException
  • 我建议使用TSourceTKey作为类型参数更符合LINQ

您可能希望将MoreLINQ MinBy实现视为替代方案.(再看一遍,我不确定我们要求comparer非空是一个好主意;如果比较器为空,它应该使用默认比较器,就像普通LINQ一样.)


Mar*_*ell 10

IComparable不提供操作员支持 - 您需要使用current.CompareTo(min).或者更好,使用Comparer<T>.Default.Compare(current,min)-那么你可以删除约束它会自动处理空值等,并且它会避免装箱.

var comparer = Comparer<T>.Default;
...
// loop
    if(comparer.Compare(current, min) < 0) {...}
Run Code Online (Sandbox Code Playgroud)