Why does a generic type constraint result in a no implicit reference conversion error?

Let’s simplify:

interface IAnimal { ... }
interface ICage<T> where T : IAnimal { void Enclose(T animal); } 
class Tiger : IAnimal { ... }
class Fish : IAnimal { ... }
class Cage<T>  : ICage<T> where T : IAnimal { ... }
ICage<IAnimal> cage = new Cage<Tiger>();

Your question is: why is the last line illegal?

Now that I have rewritten the code to simplify it, it should be clear. An ICage<IAnimal> is a cage into which you can place any animal, but a Cage<Tiger> can only hold tigers, so this must be illegal.

If it were not illegal then you could do this:

cage.Enclose(new Fish());

And hey, you just put a fish into a tiger cage.

The type system does not permit that conversion because doing so would violate the rule that the capabilities of the source type must not be less than the capabilities of the target type. (This is a form of the famous “Liskov substitution principle”.)

More specifically, I would say that you are abusing generics. The fact that you’ve made type relationships that are too complicated for you to analyze yourself is evidence that you ought to simplify the whole thing; if you’re not keeping all the type relationships straight and you wrote the thing then your users surely will not be able to keep it straight either.

Leave a Comment