继承自实现IComparable <t>?</t>的东西时,C#BinarySearch会中断

时间:2010-05-02 04:45:18

标签: c# generics inheritance sorting interface

在.NET中,如果您尝试搜索的项目从IComparable继承而不是直接实现,则BinarySearch算法(在列表,数组等中)似乎会失败:

List<B> foo = new List<B>(); // B inherits from A, which implements IComparable<A>
foo.Add(new B());
foo.BinarySearch(new B());   // InvalidOperationException, "Failed to compare two elements in the array."

其中:

public abstract class A : IComparable<A>
{
    public int x;

    public int CompareTo(A other)
    {
        return x.CompareTo(other.x);
    }
}

public class B : A {}

有解决方法吗?在B类中实现CompareTo(B other)似乎不起作用。

3 个答案:

答案 0 :(得分:7)

文档清楚地说明了这一点:

  

检查类型T是否实现IComparable通用接口并使用该实现(如果可用)。如果不是,Comparer.Default检查类型T是否实现IComparable接口。如果类型T没有实现任何一个接口,Comparer.Default会抛出InvalidOperationException。

因此,一个简单的解决方案是实现非通用接口IComparable 添加CompareTo(B other) 为您工作,只要您同时实施IComparable<B> - 您可能忘记了这一点。

一个有趣的解决方案是使用C#4编译代码,它运行时没有任何错误。 C#4引入了通用协方差:public interface IComparable<in T> vs public interface IComparable<T>,发布的代码按预期工作。

答案 1 :(得分:1)

是的,所以问题是它试图查看class B是否实现了IComparable<B>,它没有,因为它实际上实现了IComparable<A>,然后尝试IComparable然后放弃。正如Kobi指出的那样,实现非通用IComparable将解决这个问题。

答案 2 :(得分:0)

虽然上述答案对于4.0之前的.net版本是正确的,但值得注意的是.Net 4.0定义了IComparable&lt; T&gt; covariantly,这意味着如果类实现IComparable&lt; BaseType&gt;但是没有明确地实现IComparable&lt; DerivedType&gt;,IComparable&lt; BaseType&gt;的实现。将被视为IComparable&lt; DerivedType&gt;。

的实现

注意,这不适用于IEquatable&lt; T&gt;,但由于可派生类型不应实现IEquatable&lt; T&gt;。无论如何,这应该不是问题。

另请注意,与IEquatable&lt; T&gt;不同。逻辑上绑定以实现与Object.Equals非常相似的语义(因为GetHashCode实现返回不等的对象必须比较不相等),有许多情况下IComparable&lt; BaseType&gt;即使IComparable&lt; DerivedType&gt;也应该在逻辑上返回相等的应该比较不相等(在这种情况下,派生类型通常应该实现IComparable&lt; DerivedType&gt;但不能重新实现IComparable&lt; BaseType&gt;。注意,如果IComparable&lt; T&gt; .Compare返回零,那并不意味着对象相等,但仅仅是没有一个明确地排在另一个之上。