继承 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.

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