例如,我有这些类和子类。
class Program
{
static void Main(string[] args)
{
var animals = new List<Animal> { new Wolf {kills = 5},
new Rabbit {name = "Uncle John"},
new Eagle {eyeCount = 1},
new Wolf {kills = 100},
new Rabbit { name = "Human" } };
animals.Sort();
//Suposted to be: Rabbit(Human), Rabbit(Uncle John), Wolf(5), Wolf(100), Eagle(1)
}
}
enum SortOrder { Rabbit, Wolf, Eagle }
abstract class Animal{}
class Wolf : Animal
{
public int kills = 0; //Marked public for simple initialization
}
class Rabbit : Animal
{
public string name = "Funny Little Guy"; //Marked public for simple initialization
}
class Eagle : Animal
{
public byte eyeCount = 2; //Marked public for simple initialization
}
我想对动物列表进行排序。 1)在相同类型的其他对象之间进行排序(按名称对狼进行排序,按名称对兔进行排序等)2)在“SortOrder”中对子类组进行排序,因此兔子在列表中排在第一位,老鹰队排在最后。
我曾尝试通过实现IComparable<Animal>, IComparable<Wolf>, IComparable<Rabbit>, IComparable<Eagle>
接口来实现这一点,但这导致我无处可去,因为我无法完成这项工作,即使我可以,再添加一个子类会导致大量代码工作。
这是我的尝试:
abstract class Animal : IComparable<Animal>, IComparable<Wolf>, IComparable<Rabbit>, IComparable<Eagle>
{
public abstract int CompareTo(Animal other);
public abstract int CompareTo(Wolf other);
public abstract int CompareTo(Rabbit other);
public abstract int CompareTo(Eagle other);
}
class Wolf : Animal
{
public int kills = 0; //Marked public for simple initialization
public override int CompareTo(Animal other) => other.CompareTo(this);
public override int CompareTo(Wolf other) => kills.CompareTo(kills);
public override int CompareTo(Rabbit other) => SortOrder.Wolf.CompareTo(SortOrder.Rabbit);
public override int CompareTo(Eagle other) => SortOrder.Wolf.CompareTo(SortOrder.Eagle);
}
但通过这种方式,我得到了相反的顺序,而且我说很难添加新的子类。
那么进行这种比较的有效方法是什么?
答案 0 :(得分:2)
为了最小化添加新代码并强制将新类添加到层次结构中,我将进行这种设计:
首先,我会为每种具体的动物类型实施IComparable。这很简单。其次,我将SortOrder OrderType属性添加到抽象类,并在每个具体实例中实现它。这将迫使任何扩展类的人重新评估枚举并可能为其添加新值。然后,主比较函数将首先检查此属性。如果不相等,则返回类型之间的比较。如果相等,只需在两个实例上调用compare,因为可以安全地假设它们属于同一类型。
在这里实施。我实际上不得不使用反射,因为没有其他方法可以调用具体的比较器。但它似乎工作得非常好,只要实际类型对应于返回的枚举。
enum SortOrder { Rabbit, Wolf, Eagle }
abstract class Animal : IComparable<Animal>
{
public abstract SortOrder OrderType { get; }
public int CompareGeneric(Animal x, Animal y)
{
// use reflection to call comparer on concrete animal type
var comparerType = typeof(IComparable<>).MakeGenericType(x.GetType());
var compareMethod = comparerType.GetMethod("CompareTo");
return (int)compareMethod.Invoke(x, new object[] { y });
}
public int Compare(Animal x, Animal y)
{
// clever hack to compare the enums
var diff = x.OrderType - y.OrderType;
if (diff != 0)
return diff;
return CompareGeneric(x, y);
}
public int CompareTo(Animal other)
{
return Compare(this, other);
}
}
class Wolf : Animal, IComparable<Wolf>
{
public override SortOrder OrderType { get { return SortOrder.Wolf; } }
public int kills = 0; //Marked public for simple initialization
public int CompareTo(Wolf other)
{
return this.kills.CompareTo(other.kills);
}
}
class Rabbit : Animal, IComparable<Rabbit>
{
public override SortOrder OrderType { get { return SortOrder.Rabbit; } }
public string name = "Funny Little Guy"; //Marked public for simple initialization
public int CompareTo(Rabbit other)
{
return this.name.CompareTo(other.name);
}
}
class Eagle : Animal, IComparable<Eagle>
{
public override SortOrder OrderType { get { return SortOrder.Eagle; } }
public byte eyeCount = 2; //Marked public for simple initialization
public int CompareTo(Eagle other)
{
return this.eyeCount.CompareTo(other.eyeCount);
}
}
答案 1 :(得分:1)
我认为您可以使用Animal类实现IComparable,并使用只读的SortOrder枚举属性,如Euphoric所述。 然后在每个班级中,您可以覆盖CompareTo方法,将每个物种与其种类进行比较。
public abstract class Animal : IComparable
{
public abstract SortOrder SortOrder { get; }
public virtual int CompareTo(object obj)
{
Animal rightValue = (Animal)obj;
return this.SortOrder < rightValue.SortOrder ? -1
: this.SortOrder > rightValue.SortOrder ? 1 : 0;
}
}
public class Wolf : Animal
{
public override SortOrder SortOrder { get { return SortOrder.Wolf; } }
public int kills = 0; //Marked public for simple initialization
public override int CompareTo(object obj)
{
if (obj is Wolf)
{
Wolf rightValue = (Wolf)obj;
return this.kills < rightValue.kills ? -1
: this.kills > rightValue.kills ? 1 : 0;
}
else
{
return base.CompareTo(obj);
}
}
}
public class Rabbit : Animal
{
public override SortOrder SortOrder { get { return SortOrder.Rabbit; } }
public string name = "Funny Little Guy"; //Marked public for simple initialization
public override int CompareTo(object obj)
{
if (obj is Rabbit)
{
Rabbit rightValue = (Rabbit)obj;
return String.Compare(this.name, rightValue.name);
}
else
{
return base.CompareTo(obj);
}
}
}
public class Eagle : Animal
{
public override SortOrder SortOrder { get { return SortOrder.Eagle; } }
public byte eyeCount = 2; //Marked public for simple initialization
public override int CompareTo(object obj)
{
if (obj is Eagle)
{
Eagle rightValue = (Eagle)obj;
return this.eyeCount < rightValue.eyeCount ? -1
: this.eyeCount > rightValue.eyeCount ? 1 : 0;
}
else
{
return base.CompareTo(obj);
}
}
}
答案 2 :(得分:0)
我会在您的Animal类中添加一个SortKey和ICompareable接口,并在派生类中实现逻辑。
abstract class Animal : IComparable<Animal>
{
public abstract int SortKey { get; }
public abstract int CompareTo(Animal other);
}
class Wolf : Animal
{
public int kills = 0; //Marked public for simple initialization
public override int SortKey { get { return 100; } }
public override int CompareTo(Animal other)
{
if (other.SortKey != SortKey)
{
return SortKey.CompareTo(other.SortKey);
}
var otherWolf = other as Wolf;
if (otherWolf == null)
{
return -1;
}
return kills.compareTo(otherWolf.kills);
}
}
答案 3 :(得分:0)
考虑在类型中使用IComparer ;并实现IComparable以在特定类型中对进行排序。 Comparer仅对相同类型的比较调用Comparable。
优势(S):
所有类型都不需要知道类型之间的“相对”排序键。此外,基本类型不会带有额外的字段“弄脏”。 (虽然没有什么可以阻止将排序放在这样的'SortKey'字段中。)
订购动物类型的规则在一个地方被隔离,即承包商。
动物类型中的排序规则已经存在 由IComparable处理,可以覆盖/专门 对于每种类型。
缺点(S):
收集/订购操作需要使用Comparer
Comparer添加了“隐藏”逻辑,可能需要针对其他类型进行更新。 (仅当不在基本类型中使用类似SortKey的方法时才需要这样做。)
使用单独的IComparaer / IC Comparable方法是使用'SortKey'字段的更通用形式,其他排序混合到IComparable中,因为这样的字段可能被这样的IComparer使用实施
答案 4 :(得分:0)
我会用Linq解决你的问题
using System.Collections.Generic;
using System.Linq;
public enum SortOrder
{
Rabbit,
Wolf,
Eagle
}
public class Program
{
public static void Main(string[] args)
{
var animals = (new List<Animal> { new Wolf {Kills = 5},
new Rabbit {Name = "Uncle John"},
new Eagle {EyeCount = 1},
new Wolf {Kills = 100},
new Rabbit { Name = "Human" } })
.OrderBy(x => x.SortOrder)
.ThenBy(x => x.Classifier);
//Suposted to be: Rabbit(Human), Rabbit(Uncle John), Wolf(5), Wolf(100), Eagle(1)
}
}
public abstract class Animal
{
public abstract object Classifier { get; }
public string Name { get; set; }
public SortOrder SortOrder { get; set; }
}
public class Eagle : Animal
{
public Eagle()
{
this.SortOrder = SortOrder.Eagle;
}
public override object Classifier
{
get { return this.EyeCount; }
}
public byte EyeCount { get; set; }
}
public class Rabbit : Animal
{
public Rabbit()
{
this.Name = "Funny Little Guy";
this.SortOrder = SortOrder.Rabbit;
}
public override object Classifier
{
get { return this.Name; }
}
}
public class Wolf : Animal
{
public Wolf()
{
this.Name = "Funny Little Guy";
this.SortOrder = SortOrder.Wolf;
}
public override object Classifier
{
get { return this.Kills; }
}
public int Kills { get; set; }
}