在ICompareable <t>中对接口引用对象的列表进行排序

时间:2016-07-04 12:35:26

标签: c# sorting interface compareto icomparable

我在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从IComparable中获取,我的课程从IFoo和ICompareable开始,即

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();

任何人都可以解释为什么我的原始代码不起作用吗?

4 个答案:

答案 0 :(得分:3)

您的列表是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是一份合同,可以排序是一件很好的财产。

答案 1 :(得分:1)

好转的问题!

在对类型进行排序时,您希望该类型实现IComparable。

在您的原始代码中,您正在排序IFoo,它不会实现IComparable,但会在第二个中执行List<SomeBar>。这一切都有所不同。

但是如果你有一个 public GameModel getItem(int position) { return gameModelList.get(position); } 的集合,它会排序,因为它已经实现了IComparable。忽略你可能需要使用List的界面我建议你使用你的第二个解决方案。

答案 2 :(得分:1)

documentation

中描述了此行为
  

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

由于TIFoo,您的第一个示例在IFoo实现IComparable<IFoo>时有效,第二个示例失败,因为它没有。我建议您创建一个班级FooComparer : IComparer<Foo>并将其传递给other overload of Sort

答案 3 :(得分:0)

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