比较 "Apple" 和 "Orange" 对象的列表

Comparing a list of "Apple" and "Orange" objects

这更像是一个学术练习,所以我基本上只是想了解当类型不同时如何使用 IComparable。

假设我们有一个水果class,并导出classes "Apple"和"Orange"。假设我想要一份水果清单,让所有的苹果都排在橙子之前。解决此问题的最佳方法是什么?

我想你可以让 Fruit 实现接口 IComparable 并为非常子类型放入一堆条件语句,但这对我来说似乎很粗糙并且可能违反了 open/closed 原则。我更感兴趣的是让它以这种方式工作:

public abstract class Fruit : IComparable<Fruit>
{
    public abstract int CompareTo(Fruit other);
}

public class Apple : Fruit, IComparable<Orange>
{
    public override int CompareTo(Fruit other)
    {
        if(other is Orange)
        {
            this.CompareTo((Orange)other);
        }
        return 0;
    }

    public virtual int CompareTo(Orange other)
    {
        return -1;
    }
}

public class Orange : Fruit, IComparable<Apple>
{
    public override int CompareTo(Fruit other)
    {
        if (other is Apple)
        {
            this.CompareTo((Apple)other);
        }
        return 0;
    }

    public virtual int CompareTo(Apple other)
    {
        return 1;
    }
}

我的主要目标是让 IComparable 处理跨类型。我试着加载一个包含各种水果的列表,但可惜它没有排序。也许我对 CompareTo 的 return 值的理解有点靠不住。这种方法有希望吗?在任何情况下它可能比显而易见的方法更有用吗?

马上就会变得很糟糕...每个水果必须知道彼此的水果...如果您有 10 个水果,您有 90 段代码来决定如何比较它们。

我会做类似的事情:

public abstract class Fruit : IComparable<Fruit>
{
    // It should be unique for each fruit type
    public abstract int Importance { get; }

    public int CompareTo(Fruit other)
    {
        // If you want, you can do some tests here, that 
        // are common to all the Fruit. I wouldn't,
        // because this would create an ordering with
        // higher priority than Importance.

        int cmp = Importance.CompareTo(other.Importance);

        if (cmp != 0)
        {
            return cmp;
        }

        if (GetType() != other.GetType())
        {
            throw new ApplicationException("Different type of fruit must have different Importance");
        }

        // Other Fruit comparisons

        // We know the Fruit have the same type (see above)
        return CompareToInternal(other);
    }

    // Comparison of subtype of Fruit
    public abstract int CompareToInternal(Fruit other);
}

所以只有Fruit同类型才真正具有可比性。其他水果有一个预先确定的Importance(苹果比奇异果好),并且有一个抽象CompareToInternal来进行子类型比较(在同一类型的水果中......苹果与苹果,奇异果与猕猴桃)

我觉得感觉有点靠不住,因为苹果和橘子没有自然顺序。 在这个特定的例子中你更喜欢苹果胜过橘子,但也许下一个人想要的恰恰相反。还是冬天混搭?关键是 Apples 和 Oranges 没有唯一的排序算法,将其构建到 Apples 或 Oranges 甚至 Fruit 中感觉是错误的。

这就是 IComparer 的用武之地。您可以将比较逻辑放在那里,但是您可以有 许多 个比较器和 select 另一个你做的每一种。因此,您为冬天实施了一个 ApplesFirstComparer,然后实施了一个 OrangesWithTheMostOrangeColorOnTopDoNotCareForColorOfApplesComparer,一个又一个。基本上每个比较你需要一个,并不意味着苹果和橘子有一个自然的顺序。因为他们没有。

这是我的想法。这看起来很简单,但它会起作用。

您可以为每个 class 标记唯一顺序并对其进行排序。

public abstract class Fruit
{
    public int MyOrder {get;}
}

public class Apple : Fruit
{    
}

public class Orange : Fruit
{    
}

现在,您想要所有的苹果而不是橘子。设置值并排序。

//Suppose that this is your list fruits
var fruits = new List<Fruit>();
fruits.OfType<Apple>().ForEach(a=> a.MyOrder = 1);
fruits.OfType<Orange>().ForEach(a=> a.MyOrder = 2);
var sorted = fruits.OrderBy(x=>MyOrder);

缺点是如果你有 multifruit。

但是如果你的顺序没有改变,就像苹果总是在橘子之前。在class中设置MyOrder

    public abstract class Fruit
    {
        public abstract int MyOrder {get;}
    }

    public class Apple : Fruit
    {    
        public override int MyOrder {
            get { return 1;}
        }
    }

    public class Orange : Fruit
    {  
        public override int MyOrder {
            get { return 2;}
        }  
    }