我在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();
任何人都可以解释为什么我的原始代码不起作用吗?
答案 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)
此方法对类型T使用默认比较器
Comparer<T>.Default
确定列表元素的顺序。Comparer<T>.Default
属性检查类型T是否实现IComparable泛型 接口并使用该实现(如果可用)。如果不, Comparer.Default检查类型T是否实现IComparable 接口。如果类型T没有实现任何一个接口, Comparer.Default抛出InvalidOperationException。
由于T
为IFoo
,您的第一个示例在IFoo
实现IComparable<IFoo>
时有效,第二个示例失败,因为它没有。我建议您创建一个班级FooComparer : IComparer<Foo>
并将其传递给other overload of Sort。
答案 3 :(得分:0)
在您的第一个示例IFoo
实现IComparable<IFoo>
,而在第二个示例中则没有。如果您使用Array.Sort
或任何其他排序例程,则会导致ArgumentException
至少有一个对象应该实现IComparable
。