How to make an Abstract Base class IComparable that doesn't compare two separate inherited classes?
.net, c#, generics, inheritance
Solution
You can use the Curiously Recurring Template Pattern to solve this problem.
abstract class Base<T> : IComparable<T> where T : Base<T> {
public int Rank { get; set; } // Order instances of derived type T by Rank
public int CompareTo(T other) { return Rank.CompareTo(other.Rank); }
}
class Foo : Base<Foo> {}
class Bar : Base<Bar> {}
static class Program {
static void Main() {
var foo1 = new Foo { Rank = 1 };
var foo2 = new Foo { Rank = 2 };
var bar1 = new Bar { Rank = 1 };
var bar2 = new Bar { Rank = 2 };
Console.WriteLine(foo1.CompareTo(foo2));
Console.WriteLine(bar2.CompareTo(bar1));
//error CS1503: Argument '1': cannot convert from 'Bar' to 'Foo'
//Console.WriteLine(foo1.CompareTo(bar1));
}
}
Problem
(C#, VS2008) In a program I'm working on, I've got lots of objects that all have an ID and implement IComparable so that List<>-s of the various objects are easily searchable by ID. Since I hate copy/pasting code, I thought I'd abstract that bit of functionality down to a base class, like so: ``` using System; namespace MyProg.Logic { abstract class IDObject : IComparable<IDObject> { private int miID; public int ID { get { return miID; } set { miID = value; } } public IDObject(int ID) { miID = ID; } #region IComparable<IDObject> Members int IComparable<IDObject>.CompareTo(IDObject other) { return miID.CompareTo(other.miID); } #endregion } } ``` The drawback I see to that is that two separate classes that each inherit it would be directly comparable using .CompareTo() and I was hoping to enforce that each class that inherits from IDObject is only Comparable to others of the exact same class. So I was hoping to figure out how to do that and came up with this ``` using System; namespace MyProg.Logic { abstract class IDObject : IComparable<T> where T : IDObject { private int miID; public int ID { get { return miID; } set { miID = value; } } public IDObject(int ID) { miID = ID; } #region IComparable<T> Members int IComparable<T>.CompareTo(T other) { return miID.CompareTo(other.miID); } #endregion } } ``` But that gives a compile error of "Constraints are not allowed on non-generic declarations" Looking at it, I'm sure there's a way to do something like that so that each class is only comparable to other instances of that same class, but I can't tease out the syntax.