I have the following Classes / Interfaces:
// Model
public class A : IA { }
// ModelLogic
public class B : IB<A> { }
// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB<T> where T : IA { }
I try to create a new instance using the following code:
IB<IA> foo = new B();
I am getting the following error:
Cannot implicitly convert type 'B' to 'IB<IA>'. An explicit conversion exists (are you missing a cast?)
Can someone please explain why this is not possible?
OK, let's replace
A
withFish
,IA
withIAnimal
,B
withAquarium
, andIB<T>
withIContainer<T>
. And we'll add a member toIContainer<T>
, and a second implementation ofIAnimal
:You can put a Tiger into foo -- foo is typed as a container that can contain any animal. But you can only put a Fish into an Aquarium. Since the operations you can legally perform on an
Aquarium
are different than the operations you can perform on anIContainer<IAnimal>
, the types are not compatible.The feature you want is called generic interface covariance and it is supported by C# 4, but you have to prove to the compiler that you will never put a tiger into your fish tank. What you want to do is:
Notice the covariance annotation on
IB
. Thisout
means thatT
can only be used as an output, not as an input. IfT
is only an output then there is no way for someone to put a tiger into that fish tank because there is no "put into" property or method possible.I wrote a number of blog articles while we were adding that feature to C#; if you are interested in the design considerations that went into the feature, see:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/
It's not easy to see when you have empty interfaces. Consider you have one method M in interface IB:
And here is implementation of B:
Then you have object C, which also implements IA:
So, if your code would be possible, then you could call:
Problem is that class B accepts only objects of type A. Error!
To fix your code, just change
to