Foundry

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... 

It seems that when using generics, the compiler will not use the internal generic type (Base / Sub) in the generic type (OtherBase / OtherSub). Why is this happening?

Update : Also explain the difference between the above and the next (what works)

 void Call<T>() where T : Base { } //... Call<Sub>(); 
+4
source share
3 answers

Disabling this behavior (known as β€œtotal variance”) is necessary, because otherwise the following code will be compiled:

 List<string> strlist = new List<string>(); List<object> objlist = strlist; objlist.Add(42); 

We have added a number to the string list. Not good. (By the way, the code will compile for arrays instead of List , because Java allowed this for some reason, however this will result in a runtime exception.)

You can avoid this in your case:

 static void Call<U, T>(T x) where U : Base where T : OtherBase<U> { } 

And name it as follows:

 Call(new OtherSub<Sub()); 

In addition, C # 4.0 provides a common dispersion for interfaces . However, their use is often not required.

+8
source

Your problem is related to the concept of variance / covariance. In fact, if A inherits from B , Class<A> not Class<B> .

See this example:

Class<T> exposes the public method foo(T param)

If Class<A> was Class<B> , then a method that has a reference to Class<B> as Class<A> and calls foo(B param) (with instance B ) will call foo(A param) . And B not A

In fact, Class<A> can inherit from Class<B> only if T used as the return value only in Class<T> .

This is done in .NET 4 through the out keyword for the generics interface. That way, Class<T> can implement IClass<out T> .

+3
source

Konrad has some good advice on fixing your code. If you want to use C # 4 variance, you can do it like this:

 interface IOtherBase<out T> where T : Base { } class OtherBase<T> : IOtherBase<T> where T : Base { } class OtherSub<T> : OtherBase<T> where T : Base { } static void Call<T>() where T : IOtherBase<Base> { } 

Call<OtherSub<Sub>>() will work then.

+1
source

All Articles