I'm trying to figure out why the compiler is complaining about this (what I thought was a simple) inheritance scenario:
Given this abstract class..
public class AbstractAnimalValidator<TAnimal> : AbstractValidator<TAnimal>
where TAnimal: Animal<IFoo, IBar>, new()
{
}
I then try to create this concrete class...
public class CatValidator : AbstractAnimalValidator<Cat>{ }
I get this error...
Ok, so what's a Cat
?
public abstract class Animal<TFoo, TBar>
where TFoo : IFoo
where TBar : IBar { }
public class Cat : Animal<RedFoo, CleanBar> { }
I just don't get it :/ the Cat is of those two types ......
Now this is the FULL REPO on .NET Fiddle to show a live example of this.
I guess i'm also asking for is
1. why doesn't my code work? Ie. My brain says that should work, but the compiler says: given this scenario XXX .. I wouldn't know what to do ...
2. How to fix this up, so i can learn.
basically, i've read the covariance/contravariance stuff a number of times and my head keeps assploding ... especially with some crap foo/bar examples. Hopefully, with my a-little-bit-more-concrete example, I might just be able to grok this a wee bit more.
This is because Cat
is a subclass of Animal<RedFoo, CleanBar>
, AbstractAnimalValidator
expects something that is a subtype of Animal<IFoo, IBar>
but Animal<RedFoo, CleanBar>
is not a subtype of Animal<IFoo, IBar>
and thus Cat
is also not a subtype.
Please note that in this terminology subtype is a more general term then subclass. B
is a subclass of A
if B
inherits A
, and B
is a subtype of A
if a B
type object can be assigned to an A
type variable.
To fix this make the TFoo
and TBar
type parameters Covariant. This is only allowed for interfaces in C#, so you need to introduce a new interface:
public interface IAnimal<out TFoo, out TBar>
where TFoo : IFoo
where TBar : IBar { }
And use it like this:
public class AbstractAnimalValidator<TAnimal>
where TAnimal : IAnimal<IFoo, IBar>, new()
{
}
public abstract class Animal<TFoo, TBar> : IAnimal<TFoo, TBar>
where TFoo : IFoo
where TBar : IBar { }
This way Cat
becomes a subtype of IAnimal<IFoo, IBar>
, because RedFoo
is a subclass of IFoo
and CleanBar
is a subclass of IBar
.