比较实现 IComparable 的项目时出现问题

发布于 2024-10-19 03:25:04 字数 692 浏览 4 评论 0原文

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

    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;

    }

它给出了错误 Error Operator '<'不能应用于“K”和“K”类型的操作数。但我已经指定通用约束 K 应该是 Struct 和 IComparable。我相信所有的数值数据类型都可以满足这一点。

那为什么这是一个无效操作呢?

I am working on a extension method where it finds the min item by specific selector. Below the code

    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;

    }

It gives error Error Operator '<' cannot be applied to operands of type 'K' and 'K'. But i have specified the generic constraint K should be Struct and IComparable. I believe all the numeric data type can be satisfied with this.

Then how come this is a invalid operation.?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

够运 2024-10-26 03:25:04

IComparable 没有(也不能)提及任何有关运算符的信息。您应该使用:

if (current.CompareTo(min) < 0)

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

您还应该注意,因为您的约束仅讨论非泛型 IComparable界面,你将在每次操作中进行拳击。我建议您将约束更改为 IComparable 。 (或者删除约束并按照 Marc 建议使用 Comparer.Default。)

有关您的方法的其他一些注释:

  • 如果所有键值都大于 K 的默认值 (例如 K=int 并且所有键都是正数)那么您将找不到项目
  • 您可能希望有一个接受特定 IComparare 的重载(但前提是您删除了可比较的约束)
  • 没有真正需要将 K 约束为值类型。如果我想找到字典中名字最早的人怎么办?
  • 如果没有元素,则返回T的默认值;为了适应 LINQ 的其余部分,我建议抛出 InvalidOperationException
  • 我建议使用 TSourceTKey 作为类型参数,以便与LINQ

您可能需要查看 MoreLINQ MinBy 实现一个替代方案。 (再看一遍,我不确定要求 comparer 为非空对我们来说是个好主意;如果比较器为空。)

IComparable doesn't (and can't) say anything about operators. You should be using:

if (current.CompareTo(min) < 0)

Operators are static, and only ever overloaded rather than overridden. You can't require operators within interfaces, and the presence of a method doesn't magically change what an operator will do. (For example, overriding Equals does not change how == behaves.)

You should also note that as your constraint only talks about the nongeneric IComparable interface, you're going to be boxing at every operation. I would suggest you change the constraint to IComparable<K> instead. (Or drop the constraint and just use Comparer<K>.Default as Marc suggested.)

Some other comments about your method:

  • If all of the key values are more than the default value for K (e.g. K=int and all the keys are positive) then you won't find an item
  • You may wish to have an overload which accepts a particular IComparare<K> (but only if you drop the comparable constraint)
  • There's no real need to constrain K to a value type. What if I wanted to find the person with the lexicographically earliest name?
  • If there are no elements, it will return the default value for T; to fit in with the rest of LINQ I would suggest throwing InvalidOperationException
  • I would suggest using TSource and TKey as the type parameters to be more consistent with LINQ

You may want to look at the MoreLINQ MinBy implementation as an alternative. (Looking over that again, I'm not sure it's a good idea for us to require that comparer is non-null; it should probably use the default comparer in the same way as normal LINQ does if the comparer is null.)

真心难拥有 2024-10-26 03:25:04

IComparable 不提供运算符支持 - 您需要使用current.CompareTo(min)。或者更好的是,使用 Comparer.Default.Compare(current,min) - 然后您可以删除约束并且它会自动处理空值等,并且它会避免拳击。

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

IComparable doesn't provide operator support - you need to use current.CompareTo(min). Or better, use Comparer<T>.Default.Compare(current,min) - then you can drop the constraint and it'll handle nulls etc automatically, and it'll avoid boxing.

var comparer = Comparer<T>.Default;
...
// loop
    if(comparer.Compare(current, min) < 0) {...}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文