2010-05-02 48 views
5

在.NET中的二分查找算法(在列表,数组等)出现故障,如果你想搜索的项目从IComparable的继承直接实现它,而不是:C#BinarySearch从实现IComparable <T>的东西继承时破坏?

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)似乎不起作用。

+0

此代码在我的C#编译器上生成运行状况良好 – Stewart 2010-05-02 04:57:26

+0

@Stewart - 您可能正在使用C#4. – Kobi 2010-05-02 05:16:41

+0

@Kobi - 哎呀,很对。我忘了这个改变了,问题没有提到一个版本。 – Stewart 2010-05-02 05:38:12

回答

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>,并且发布的代码按预期工作。

+5

逆变换FTW! – 2010-05-02 16:25:16

1

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

0

虽然上面的答案之前,4.0是.NET版本是正确的,但值得注意的是.NET 4.0定义了IComparable <牛逼>协变,这意味着如果该类实现了IComparable <BASETYPE>但并未明确实现IComparable <DerivedType>,如果IComparable <BaseType>将实施如果IComparable <DerivedType>将实施。

注意,这并不适用于IEquatable <牛逼>,但由于中导出的类型不应该执行IEquatable <牛逼>无论如何,这不应该是一个问题。

还要注意,不像IEquatable <牛逼>这在逻辑上必然要实现语义非常相似的Object.Equals(因为其对象的GetHashCode实现返回不平等必须比较不等),有很多情形下,IComparable的<BASETYPE>应即使IComparable <DerivedType>应该比较不等于(在这种情况下,派生类型应该通常实现IComparable <DerivedType>但不能实现IComparable <BaseType>。请注意,如果IComparable的<牛逼> .Compare返回零,这并不意味着该对象是等于,但仅仅是没有一个明确居上方。