Ответ 1
ОК, замените A
на Fish
, IA
на IAnimal
, B
на Aquarium
и IB<T>
на IContainer<T>
. И мы добавим элемент в IContainer<T>
, а вторую реализацию IAnimal
:
// Model
public class Fish : IAnimal { }
public class Tiger : IAnimal { }
// ModelLogic
public class Aquarium : IContainer<Fish>
{
public Fish Contents { get; set; }
}
// Model Interface
public interface IAnimal { }
// ModelLogic Interface
public interface IContainer<T> where T : IAnimal
{
T Contents { get; set; }
}
IContainer<IAnimal> foo = new Aquarium(); // Why is this illegal?
foo.Contents = new Tiger(); // Because this is legal!
Вы можете поместить Tiger в foo - foo вводится как контейнер, который может содержать любое животное. Но вы можете поместить Рыбу в Аквариум. Поскольку операции, которые вы можете законно выполнять на Aquarium
, отличаются от операций, которые вы можете выполнять на IContainer<IAnimal>
, типы несовместимы.
Функция, которую вы хотите, называется общей ковариацией интерфейса, и она поддерживается С# 4, но вам нужно доказать, что вы никогда не ставите тигра в свой аквариум. Что вы хотите сделать:
// Model
public class A : IA { }
// ModelLogic
public class B : IB<A> { }
// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB<out T> where T : IA { }
Обратите внимание на аннотацию ковариации на IB
. Этот out
означает, что T
может использоваться только как выходной, а не как вход. Если T
- это только выход, то нет возможности кому-то поставить тигра в этот аквариум, потому что нет возможности "вставить" или способ.
Я написал несколько статей в блогах, пока мы добавляли эту функцию в С#; если вас интересуют соображения дизайна, которые вошли в эту функцию, см.:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/