比较 "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;}
}
}
这更像是一个学术练习,所以我基本上只是想了解当类型不同时如何使用 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;}
}
}