继承iccomparable 的接口引用对象排序列表

本文关键字:引用 对象 排序 列表 接口 iccomparable 继承 | 更新日期: 2023-09-27 17:55:04

对于指向不同类型的接口引用列表,我在list.Sort()中遇到了麻烦,但是问题Sort a list of interface objects提供了以下解决方案

interface IFoo : IComparable<IFoo> 
{ 
    int Value { get; set; } 
}
class SomeFoo : IFoo
{
    public int Value { get; set; }
    public int CompareTo(IFoo other)
    {
        // implement your custom comparison here...
    }
}

在我的原始代码中,而不是IFoo从iccomparable继承,我的类同时继承了IFoo和iccomparable,即

interface IFoo
{ 
    int Value { get; set; } 
}
class SomeFoo : IFoo, IComparable<IFoo> 
{
    public int Value { get; set; }
    public int CompareTo(IFoo other)
    {
        // implement your custom comparison here...
    }
}
class SomeBar : IFoo, IComparable<IFoo> 
{
    public int Value { get; set; }
    public int CompareTo(IFoo other)
    {
        // implement your custom comparison here...
    }
}

但是当我试图对IFoo引用列表进行排序时,我得到了错误Failed to compare two elements in the array.

List<IFoo> iFoos = new List<IFoo> 
{
    new SomeFoo{Value = 1},
    new SomeFoo{Value = 15},
    new SomeFoo{Value = 390},
    new SomeBar{Value = 2},
    new SomeBar{Value = 78},
    new SomeBar{Value = 134}
}
iFoos.Sort();

谁能解释为什么我原来的代码不能工作?

继承iccomparable <T>的接口引用对象排序列表

您的列表是IFoo的列表。因此,从列表(及其排序操作)的角度来看,它只看到接口,而不知道具体类型的任何信息。

所以当它试图订购两个IFoo时,它不能这样做,因为IFoo不实现IComparable

问题是,仅仅因为您的两个类型分别实现IComparable<Foo>,所以不能保证列表中的所有 IFoo元素都这样做。因此操作是不安全的。

为了能够使用IComparable<IFoo>对元素进行排序,IFoo接口需要实现接口本身。


或者,您也可以实现IComparer<IFoo>并将其传递给Sort(),然后将其委托给各自的实际实现。当然,这并不是一个真正优雅的解决方案,也不是很未来的证明(如果您创建了IFoo的新实现):

class FooComparer : IComparer<IFoo>
{
    public int Compare(IFoo a, IFoo b)
    {
        if (a is SomeFoo)
            return ((SomeFoo)a).CompareTo(b);
        else if (a is SomeBar)
            return ((SomeBar)a).CompareTo(b);
        else
            throw new NotImplementedException("Comparing neither SomeFoo nor SomeBar");
    }
}

当然,如果您的意思是IFoo是可比较的,您应该让该接口直接实现IComparable<IFoo>,而不是依靠子类型来实现。IFoo是一个契约,可排序是一个很好的属性。

很好的问题!

当你对一个类型进行排序时,你希望这个类型实现icomcomparable。

在你的原始代码中,你正在排序IFoo,它不实现IComparable,但在第二个代码中它做到了。这就是一切的不同。

但是如果你有一个List<SomeBar>的集合,它会排序,因为它有IComparable实现。忽略您可能需要使用List的接口,我建议您使用第二个解决方案。

此行为在文档中有描述:

该方法对类型T使用默认比较器Comparer<T>.Default确定列表元素的顺序。的Comparer<T>.Default属性检查类型T是否实现了icomable泛型接口并使用该实现(如果可用)。如果不是这样,比较器。Default检查类型T是否实现IComparable接口。如果类型T没有实现任何接口,比较器。Default抛出InvalidOperationException。

由于TIFoo,当IFoo实现IComparable<IFoo>时,您的第一个示例工作,而第二个示例失败,因为它没有。我建议您创建一个类FooComparer : IComparer<Foo>并将其传递给Sort的另一个重载。

在第一个示例中,IFoo实现了IComparable<IFoo>,而在第二个示例中没有。如果您使用Array.Sort或任何其他排序例程,它将导致ArgumentException,至少有一个对象应该实现IComparable