In case it is not clear why your program is illegal, let me rename your classes:
public class Cage<C, A>
where C : Cage<C, A>
where A : Animal<C>
{
public M(A animal)
{
animal.SetCage(this); // Why is this illegal?
}
}
class Animal<C>
{
public void SetCage(C c) {}
}
class Fish : Animal<Aquarium> {}
class Aquarium : Cage<Aquarium, Fish> { }
The question is: why is animal.SetCage(this);
illegal? Well, to be legal that line has to be type safe for every possible legal construction of Cage and Animal. That's what it means for a type safety system to be sound; you don't get to be type safe just some of the time.
Can we construct a scenario where we have legal Cage
and Animal
types but the call to animal.SetCage()
is wrong? We certainly can.
class SharkTank : Cage<Aquarium, Fish> { }
Obviously this is legal; Cage<Aquarium, Fish>
was a legal base type for Aquarium
so it should be a legal base type for any type!
Now what happens when we call:
var s = new SharkTank();
var f = new Fish();
s.M(f);
s.M(f)
calls Fish.SetCage(this)
which expects an Aquarium
. But this
is not of type Aquarium
! this
is of type SharkTank
, which cannot be converted to Aquarium
. SharkTank
and Aquarium
have the same base type, and two different class types that have the same base type are not implicitly convertible to each other.
What you are trying to do here is create a constraint that means "the generic type is guaranteed to be constructed with its own type as a type parameter" but there is no way to express that constraint in C#. Instead of tying yourself in knots like this creating recursively defined types with constraints that refer to themselves, make your type system a lot simpler. Whatever constraint it is that you are trying to impose can be imposed by runtime policy rather than attempting to capture it in the type system. The type system is not that strong! Don't try to make it enforce rules it was not designed to enforce.
If this subject interests you, see my articles about this pattern specifically:
https://ericlippert.com/2011/02/02/curiouser-and-curiouser/
And about the general problem of trying to put too many rules into the type system:
https://ericlippert.com/2015/04/27/wizards-and-warriors-part-one/