It is easier to see why what you are trying to do cannot work without some modifications by adding a method to one of your classes:
public class LivingThing<TExtremity> where TExtremity : Appendage {
private TExtremity extremity;
public void SetExtremity(TExtremity e) {
extremity = e;
}
}
Now let's imagine that C# lets you do your assignment. Then it should let you do this:
public class Hand : Appendage { }
...
// Let's pretend this works
LivingThing<Appendage> cat = new Cat();
// Now that C# let us do the assignment above, it must allow this too,
// because Cat is a LivingThing and Hand is an Appendage:
cat.SetExtremity(new Hand());
Oops, we've got a Cat with a Hand! C# should not let us do this.
Doing what you wish to do may be possible if LivingThing
had methods that return TExtremity
, though. C# provides means for defining inheritance hierarchies that give you flexibility of assignments along the lines of what you tried. Here is your modified code that works:
void Main()
{
ILivingThing<Appendage> mysteryAnimal = new Cat();
}
public class Appendage { }
public class Paw : Appendage { }
public interface ILivingThing<out TExtremity> where TExtremity : Appendage { }
// You have a choice of keeping Animal a class. If you do, the assignment
// Animal<Appendage> mysteryAnimal = new Cat()
// would be prohibited.
public interface IAnimal<TExtremity> : ILivingThing<out TExtremity> where TExtremity : Appendage { }
public class Cat : Animal<Paw> { }
There is a catch: neither ILivingThing<TExtremity>
nor IAnimal<TExtremity>
is allowed to have settable properties of type TExtremity
or methods that take TExtremity
as an argument.