interface Base { ... }
class Sub : Base { ... }
class OtherBase<T> where T : Base { ... }
class OtherSub<T> : OtherBase<T> where T : Base { ... }
//...in some class
void Call<T>() where T : OtherBase<Base> { }
//...
Call<OtherSub<Sub>>(); //compile fails...
Seems like when using generics, the compiler won't cast a inner generic type (Base/Sub) in the generic type (OtherBase/OtherSub). Why does this happen?
Update: Please also explain the difference between the above and the following (which works)
void Call<T>() where T : Base { }
//...
Call<Sub>();
Forbidding this behaviour (known as “generic variance”) is necessary because otherwise the following code would compile:
List<string> strlist = new List<string>();
List<object> objlist = strlist;
objlist.Add(42);
We’ve added a number to a list of strings. Not good. (Incidentally, the code would compile for arrays instead of Lists because Java allowed this for some reason; however, this will raise a runtime exception.)
You can avoid this in your case though:
static void Call<U, T>(T x) where U : Base where T : OtherBase<U> { }
And call it like this:
Call(new OtherSub<Sub());
C# 4.0 furthermore provides generic variance for interfaces. However, their use isn’t often necessary.
Your issue is linked to a concept called variance/covariance. In fact, if A inherits from B, Class<A> isn't a Class<B>.
See this example:
Class<T> exposes a public method foo(T param)
If Class<A> was a Class<B>, then a method having a reference to Class<B> as a Class<A> and calling foo(B param) (with a B instance) would be calling foo(A param). And B isn't a A.
In fact, Class<A> can inherit from Class<B> only if T is used as a return value only in Class<T>.
This is enforced in .NET 4 through the out keyword for generics interface. Class<T> could therefore implement IClass<out T>.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With