Just some sample classes here. I try to use polymorphism in gerneric Lists, so I want each list to use its own CompareTo-Method. I don't want to find a different class arrangement. I want to understand why that is not working.
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");
}
}
Why is MyAnimals.Sort() not using the CompareTo() in Animal class? Is there a way to use polymorhpism as it is meant to be? So that List of Animals is Compared by AnimalMethod and Dogs List by Dogs CompareTo Method and so on?
The problem here is that the
DogandCatclasses have aCompareTomethod that hides the base-class method, and becauseSortwill use theComapareTomethod of the item's actual type instead of the type defined for the items on theList<T>, you will get an exception when trying to compare aDogwith aCat.One way to resolve this is to implement the
IComparable<T>interface instead, so that we specify the exact type we want to compare an object with. This way, the correct implementation will be used by theSortmethod.Also note that instead of re-implementing the
CompareTomethod ofAnimal(which compares theNameproperties) for each derived class, we can simply callbase.CompareTo(other)from the derived class'sCompareTomethod when necessary:Also, you might want to change your
ShowListmethod to show the typeTrather then the derived type of the first element in the list (otherwise theList<Animal>displays that it's aList<Dog>because the first item is aDog):