继承 IComparable<T> 的接口引用对象排序列表
Sorting list of interface reference objects inherting ICompareable<T>
我在使用 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 继承,我的 class 是从 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();
谁能解释为什么我的原始代码不起作用?
在您的第一个示例中,IFoo
实现了 IComparable<IFoo>
,而在第二个示例中则没有。如果您使用 Array.Sort
或任何其他排序例程,它将导致 ArgumentException
至少一个对象应实现 IComparable
.
您的列表是 IFoo
的列表。所以从列表(及其排序操作)的角度来看,它只看到该接口而不知道具体类型。
所以当它试图订购两个 IFoo
时,它不能这样做,因为 IFoo
没有实现 IComparable
.
问题在于,仅仅因为您的两种类型分别实现了 IComparable<Foo>
,无法保证列表中的 all 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
是一个合同,可排序是一个很好的 属性 要求。
好问题!
当您对类型进行排序时,您希望该类型实现 IComparable。
在您的原始代码中,您正在对 IFoo
进行排序,它没有实现 IComparable
但在第二个代码中它实现了。这让一切变得不同。
但是如果你有一个 List<SomeBar>
的集合,它会排序,因为它实现了 IComparable。忽略您可能需要使用 List 的接口,我建议您使用第二个解决方案。
documentation 中描述了此行为:
This method uses the default comparer Comparer<T>.Default
for type T
to determine the order of list elements. The Comparer<T>.Default
property checks whether type T implements the IComparable generic
interface and uses that implementation, if available. If not,
Comparer.Default checks whether type T implements the IComparable
interface. If type T does not implement either interface,
Comparer.Default throws an InvalidOperationException.
由于 T
是 IFoo
,您的第一个示例在 IFoo
实现 IComparable<IFoo>
时有效,而第二个示例失败,因为它没有实现。我建议您创建一个 class FooComparer : IComparer<Foo>
并将其传递给 other overload of Sort.
我在使用 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 继承,我的 class 是从 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();
谁能解释为什么我的原始代码不起作用?
在您的第一个示例中,IFoo
实现了 IComparable<IFoo>
,而在第二个示例中则没有。如果您使用 Array.Sort
或任何其他排序例程,它将导致 ArgumentException
至少一个对象应实现 IComparable
.
您的列表是 IFoo
的列表。所以从列表(及其排序操作)的角度来看,它只看到该接口而不知道具体类型。
所以当它试图订购两个 IFoo
时,它不能这样做,因为 IFoo
没有实现 IComparable
.
问题在于,仅仅因为您的两种类型分别实现了 IComparable<Foo>
,无法保证列表中的 all 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
是一个合同,可排序是一个很好的 属性 要求。
好问题!
当您对类型进行排序时,您希望该类型实现 IComparable。
在您的原始代码中,您正在对 IFoo
进行排序,它没有实现 IComparable
但在第二个代码中它实现了。这让一切变得不同。
但是如果你有一个 List<SomeBar>
的集合,它会排序,因为它实现了 IComparable。忽略您可能需要使用 List 的接口,我建议您使用第二个解决方案。
documentation 中描述了此行为:
This method uses the default comparer
Comparer<T>.Default
for type T to determine the order of list elements. TheComparer<T>.Default
property checks whether type T implements the IComparable generic interface and uses that implementation, if available. If not, Comparer.Default checks whether type T implements the IComparable interface. If type T does not implement either interface, Comparer.Default throws an InvalidOperationException.
由于 T
是 IFoo
,您的第一个示例在 IFoo
实现 IComparable<IFoo>
时有效,而第二个示例失败,因为它没有实现。我建议您创建一个 class FooComparer : IComparer<Foo>
并将其传递给 other overload of Sort.