I have the following Classes / Interfaces:
// Model
public class A : IA { }
// ModelLogic
public class B : IB { }
// Model Interface
public interfa
OK, let's replace A with Fish, IA with IAnimal, B with Aquarium, and IB with IContainer. And we'll add a member to IContainer, and a second implementation of IAnimal:
// Model
public class Fish : IAnimal { }
public class Tiger : IAnimal { }
// ModelLogic
public class Aquarium : IContainer
{
public Fish Contents { get; set; }
}
// Model Interface
public interface IAnimal { }
// ModelLogic Interface
public interface IContainer where T : IAnimal
{
T Contents { get; set; }
}
IContainer foo = new Aquarium(); // Why is this illegal?
foo.Contents = new Tiger(); // Because this is legal!
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 an IContainer, 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:
// Model
public class A : IA { }
// ModelLogic
public class B : IB { }
// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB where T : IA { }
Notice the covariance annotation on IB. This out means that T can only be used as an output, not as an input. If T 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/