Suppose I have
class Program
{
static void Main(string[] args)
{
Apple myApple = new Apple(5);
Orange myOrange = new Orange(5);
bool isSame = myApple.Compare(myOrange);
}
}
class Fruit
{
private readonly int _Size;
public Fruit(int size)
{
_Size = size;
}
public bool Compare<T>(T otherFruit) where T : Fruit
{
if (this._Size == otherFruit._Size) return true;
return false;
}
}
class Apple : Fruit
{
public Apple(int size) : base(size) { }
}
class Orange : Fruit
{
public Orange(int size) : base(size) { }
}
And I don't want to compare Apples to Oranges. I know I can
public bool Compare<T>(T otherFruit) where T : Fruit
{
if (this.GetType() != otherFruit.GetType()) return false;
if (this._Size == otherFruit._Size) return true;
return false;
}
But it feels like I should be able to do it with type constraints.
I can do this (even though it's ugly) and it looks like it would work, but doesn't do what I expect
public bool Compare<T>(T otherFruit) where T : Fruit
{
return Compare(otherFruit, this);
}
public static bool Compare<T>(T fruit1, T fruit2) where T : Fruit
{
if (fruit1._Size == fruit2._Size) return true;
return false;
}
How can I make it so my Compare method, defined in the base class, when run in child classes only allows a parameter type matching the child class? (So ideally at compile time you can only compare Apples to Apples and Oranges to Oranges)?
Interestingly, if I replace the instance compare method with an extension method, it does what I want / expect (I get compile time checks that I am only comparing Apples to Apples)
static class FruitComparer
{
public static bool Compare<T>(this T currentFruit, T otherFruit) where T : Fruit
{
return Fruit.Compare(currentFruit, otherFruit);
}
}
but again, it seems like there should be an easier way to do it... maybe I'm missing something super obvious?
EDIT: this actually works (you get compile time checks that only Apples can be compared to Apples), but only if called directly
public static bool Compare<T, U>(T fruit1, U fruit2) where T:Fruit,U where U:Fruit
{
if (fruit1._Size == fruit2._Size) return true;
return false;
}
Strangely, if you call that static method from inside my instance compare method, you do NOT get compile time checks - it lets you compare Apples to Oranges.
EDIT2: Here's how this would be implemented according the the linked question / Peter's comments
class Fruit<X>
{
private readonly int _Size;
public Fruit(int size)
{
_Size = size;
}
public bool Compare<T>(Fruit<T> otherFruit) where T: Fruit<X>
{
return true;
}
}
class Apple : Fruit<Apple>
{
public Apple(int size) : base(size) { }
}
class Orange : Fruit<Orange>
{
public Orange(int size) : base(size) { }
}
And it does seem to work, but it feels like a lot of extra stuff just to get type constraints, and the apparent self reference feels weird to me. Maybe that's as good as it gets. I'm going to see if I can find more information about this pattern.