在具有不同继承相关类型的 T 的列表 <T> 中使用 IComparable
Using IComparable in list<T> with different inheritance related types of T
这里只是一些示例 class。我尝试在通用列表中使用多态性,所以我希望每个列表都使用自己的 CompareTo-Method。我不想找到不同的 class 安排。我想了解为什么这不起作用。
class Program
{
static void Main(string[] args)
{
List<Animal> MyAnimals = new List<Animal>();
MyAnimals.Add(new Dog() { Name = "karl", Number = 1 });
MyAnimals.Add(new Dog() { Name = "carla", Number = 2 });
MyAnimals.Add(new Dog() { Name = "loki", Number = 3 });
MyAnimals.Add(new Cat() { Name = "karsten", Size = 3 });
MyAnimals.Add(new Cat() { Name = "charlie", Size = 5 });
MyAnimals.Add(new Cat() { Name = "mona", Size = 1 });
MyAnimals.Add(new Cat() { Name = "sisi", Size = 2 });
MyAnimals.Sort();
ShowList(MyAnimals);
List<Cat> cats = new List<Cat>();
List<Dog> dogs = new List<Dog>();
foreach (var item in MyAnimals)
{
if (item is Cat)
cats.Add(item as Cat);
if (item is Dog)
dogs.Add(item as Dog);
}
dogs.Reverse();
dogs.Sort();
cats.Sort();
ShowList(dogs);
ShowList(cats);
Console.ReadKey();
}
private static void ShowList<T>(List<T> MyAnimals)
{
Console.WriteLine("List of "+MyAnimals[0].GetType().Name);
foreach (var item in MyAnimals)
{
Console.WriteLine(item);
}
}
}
abstract class Animal : IComparable{
public string Name { get; set; }
public int CompareTo(object obj)
{
if (obj == null) return 1;
Animal animal = obj as Animal;
if (animal != null)
return this.Name.CompareTo(animal.Name);
else
throw new ArgumentException("Object is not a Animal");
}
public override string ToString()
{
return Name;
}
}
class Dog : Animal, IComparable
{
public int Number { get; set; }
public override string ToString()
{
return base.ToString() + "\tNumber:"+ Number + "\n";
}
public int CompareTo(object obj)
{
if (obj == null) return 1;
if (obj is Dog animal)
if (this.Number.CompareTo(animal.Number) == 0)
{
return this.Name.CompareTo(animal.Name);
}
else
{
return this.Number.CompareTo(animal.Number);
}
else
throw new ArgumentException("Object is not a Dog");
}
}
class Cat : Animal, IComparable
{
public int Size { get; set; }
public override string ToString()
{
return base.ToString() + "\tNumber:" + Size + "\n";
}
public new int CompareTo(object obj)
{
if (obj == null) return 1;
if (obj is Cat animal)
if (this.Size.CompareTo(animal.Size) == 0)
{
return this.Name.CompareTo(animal.Name);
}
else
{
return this.Size.CompareTo(animal.Size);
}
else
throw new ArgumentException("Object is not a Cat");
}
}
为什么 MyAnimals.Sort()
不使用 Animal class 中的 CompareTo()
?有没有一种方法可以像预期的那样使用多态性?所以动物列表是通过 AnimalMethod 比较的,狗列表是通过 Dogs CompareTo 方法等等?
当使用 IComparable
对列表进行排序时。被调用的 CompareTo
方法始终是在对象本身的类型上定义的方法,而不是在您为列表定义的类型上定义的方法。因为 Cat
和 Dog
覆盖 CompareTo
因此 Sort
方法永远不会在 Animal
.
中使用 CompareTo
你可以做的是使用重载 public void Sort (Comparison<T> comparison)
:
private int CompareAnimals(Animal animA, Animal animB)
{
// ... your logic to compare two Animals
}
private int CompareCats(Cat catA, Cat catB)
{
// ... your logic to compare two Cats
}
private int CompareDogs(Dog dogA, Dog dogB)
{
// ... your logic to compare two Dogs
}
static void Main(string[] args)
{
List<Animal> MyAnimals = new List<Animal>();
// Adding animals...
MyAnimals.Sort(CompareAnimals);
// ...
dogs.Sort(CompareDogs);
cats.Sort(CompareCats);
}
这里的问题是 Dog
和 Cat
classes 有一个 CompareTo
方法 隐藏 base-class 方法,因为 Sort
将使用项目实际类型的 ComapareTo
方法,而不是为 [=17] 上的项目定义的类型=], 你会在尝试比较 Dog
和 Cat
.
时得到一个异常
解决这个问题的一种方法是改为实现 IComparable<T>
接口,以便我们指定要与对象进行比较的确切类型。这样,Sort
方法将使用正确的实现。
另请注意,对于每个派生的 class,我们可以代替 re-implementing Animal
的 CompareTo
方法(比较 Name
属性)只需在必要时从派生的 class 的 CompareTo
方法中调用 base.CompareTo(other)
:
abstract class Animal : IComparable<Animal>
{
public string Name { get; set; }
public int CompareTo(Animal other)
{
if (other == null) return 1;
return string.Compare(Name, other.Name);
}
public override string ToString()
{
return Name;
}
}
class Dog : Animal, IComparable<Dog>
{
public int Number { get; set; }
public override string ToString()
{
return base.ToString() + "\tNumber:" + Number + "\n";
}
public int CompareTo(Dog other)
{
if (other == null) return 1;
var numberCompare = Number.CompareTo(other.Number);
return numberCompare == 0 ? base.CompareTo(other) : numberCompare;
}
}
class Cat : Animal, IComparable<Cat>
{
public int Size { get; set; }
public override string ToString()
{
return base.ToString() + "\tNumber:" + Size + "\n";
}
public int CompareTo(Cat other)
{
if (other == null) return 1;
var sizeCompare = Size.CompareTo(other.Size);
return sizeCompare == 0 ? base.CompareTo(other) : sizeCompare;
}
}
此外,您可能希望更改 ShowList
方法以显示类型 T
而不是列表中第一个元素的派生类型(否则 List<Animal>
显示这是 List<Dog>
因为第一项是 Dog
):
private static void ShowList<T>(List<T> MyAnimals)
{
Console.WriteLine("List of " + typeof(T).Name);
foreach (var item in MyAnimals)
{
Console.WriteLine(item);
}
}
这里只是一些示例 class。我尝试在通用列表中使用多态性,所以我希望每个列表都使用自己的 CompareTo-Method。我不想找到不同的 class 安排。我想了解为什么这不起作用。
class Program
{
static void Main(string[] args)
{
List<Animal> MyAnimals = new List<Animal>();
MyAnimals.Add(new Dog() { Name = "karl", Number = 1 });
MyAnimals.Add(new Dog() { Name = "carla", Number = 2 });
MyAnimals.Add(new Dog() { Name = "loki", Number = 3 });
MyAnimals.Add(new Cat() { Name = "karsten", Size = 3 });
MyAnimals.Add(new Cat() { Name = "charlie", Size = 5 });
MyAnimals.Add(new Cat() { Name = "mona", Size = 1 });
MyAnimals.Add(new Cat() { Name = "sisi", Size = 2 });
MyAnimals.Sort();
ShowList(MyAnimals);
List<Cat> cats = new List<Cat>();
List<Dog> dogs = new List<Dog>();
foreach (var item in MyAnimals)
{
if (item is Cat)
cats.Add(item as Cat);
if (item is Dog)
dogs.Add(item as Dog);
}
dogs.Reverse();
dogs.Sort();
cats.Sort();
ShowList(dogs);
ShowList(cats);
Console.ReadKey();
}
private static void ShowList<T>(List<T> MyAnimals)
{
Console.WriteLine("List of "+MyAnimals[0].GetType().Name);
foreach (var item in MyAnimals)
{
Console.WriteLine(item);
}
}
}
abstract class Animal : IComparable{
public string Name { get; set; }
public int CompareTo(object obj)
{
if (obj == null) return 1;
Animal animal = obj as Animal;
if (animal != null)
return this.Name.CompareTo(animal.Name);
else
throw new ArgumentException("Object is not a Animal");
}
public override string ToString()
{
return Name;
}
}
class Dog : Animal, IComparable
{
public int Number { get; set; }
public override string ToString()
{
return base.ToString() + "\tNumber:"+ Number + "\n";
}
public int CompareTo(object obj)
{
if (obj == null) return 1;
if (obj is Dog animal)
if (this.Number.CompareTo(animal.Number) == 0)
{
return this.Name.CompareTo(animal.Name);
}
else
{
return this.Number.CompareTo(animal.Number);
}
else
throw new ArgumentException("Object is not a Dog");
}
}
class Cat : Animal, IComparable
{
public int Size { get; set; }
public override string ToString()
{
return base.ToString() + "\tNumber:" + Size + "\n";
}
public new int CompareTo(object obj)
{
if (obj == null) return 1;
if (obj is Cat animal)
if (this.Size.CompareTo(animal.Size) == 0)
{
return this.Name.CompareTo(animal.Name);
}
else
{
return this.Size.CompareTo(animal.Size);
}
else
throw new ArgumentException("Object is not a Cat");
}
}
为什么 MyAnimals.Sort()
不使用 Animal class 中的 CompareTo()
?有没有一种方法可以像预期的那样使用多态性?所以动物列表是通过 AnimalMethod 比较的,狗列表是通过 Dogs CompareTo 方法等等?
当使用 IComparable
对列表进行排序时。被调用的 CompareTo
方法始终是在对象本身的类型上定义的方法,而不是在您为列表定义的类型上定义的方法。因为 Cat
和 Dog
覆盖 CompareTo
因此 Sort
方法永远不会在 Animal
.
CompareTo
你可以做的是使用重载 public void Sort (Comparison<T> comparison)
:
private int CompareAnimals(Animal animA, Animal animB)
{
// ... your logic to compare two Animals
}
private int CompareCats(Cat catA, Cat catB)
{
// ... your logic to compare two Cats
}
private int CompareDogs(Dog dogA, Dog dogB)
{
// ... your logic to compare two Dogs
}
static void Main(string[] args)
{
List<Animal> MyAnimals = new List<Animal>();
// Adding animals...
MyAnimals.Sort(CompareAnimals);
// ...
dogs.Sort(CompareDogs);
cats.Sort(CompareCats);
}
这里的问题是 Dog
和 Cat
classes 有一个 CompareTo
方法 隐藏 base-class 方法,因为 Sort
将使用项目实际类型的 ComapareTo
方法,而不是为 [=17] 上的项目定义的类型=], 你会在尝试比较 Dog
和 Cat
.
解决这个问题的一种方法是改为实现 IComparable<T>
接口,以便我们指定要与对象进行比较的确切类型。这样,Sort
方法将使用正确的实现。
另请注意,对于每个派生的 class,我们可以代替 re-implementing Animal
的 CompareTo
方法(比较 Name
属性)只需在必要时从派生的 class 的 CompareTo
方法中调用 base.CompareTo(other)
:
abstract class Animal : IComparable<Animal>
{
public string Name { get; set; }
public int CompareTo(Animal other)
{
if (other == null) return 1;
return string.Compare(Name, other.Name);
}
public override string ToString()
{
return Name;
}
}
class Dog : Animal, IComparable<Dog>
{
public int Number { get; set; }
public override string ToString()
{
return base.ToString() + "\tNumber:" + Number + "\n";
}
public int CompareTo(Dog other)
{
if (other == null) return 1;
var numberCompare = Number.CompareTo(other.Number);
return numberCompare == 0 ? base.CompareTo(other) : numberCompare;
}
}
class Cat : Animal, IComparable<Cat>
{
public int Size { get; set; }
public override string ToString()
{
return base.ToString() + "\tNumber:" + Size + "\n";
}
public int CompareTo(Cat other)
{
if (other == null) return 1;
var sizeCompare = Size.CompareTo(other.Size);
return sizeCompare == 0 ? base.CompareTo(other) : sizeCompare;
}
}
此外,您可能希望更改 ShowList
方法以显示类型 T
而不是列表中第一个元素的派生类型(否则 List<Animal>
显示这是 List<Dog>
因为第一项是 Dog
):
private static void ShowList<T>(List<T> MyAnimals)
{
Console.WriteLine("List of " + typeof(T).Name);
foreach (var item in MyAnimals)
{
Console.WriteLine(item);
}
}