Давайте сделаем это немного легче для понимания:
abstract class Animal {} // was AConfigAction
abstract class Cage<T> where T : Animal {} // was APlugIn
class Tiger : Animal {} // was AppExecuteConfigAction
class TigerCage : Cage<Tiger>{} // was AppExecutePlugin
var cages = new List<Cage<Animal>>();
cages.Add(new TigerCage()); // Why is this an error?
Предположим, это было законно.Что останавливает это?
class Shark : Animal {} // some other config action
...
var cages = new List<Cage<Animal>>();
cages.Add(new TigerCage());
Cage<Animal> firstCage = cages[0];
firstCage.InsertIntoCage(new Shark());
firstCage имеет тип Cage<Animal>
, что означает, что он может содержать любое животное.Но на самом деле мы знаем, что это клетка только для тигров.Вы просто помещаете акулу в клетку с тигром, что кажется неудобным как для акулы, так и для тигра.
Очевидно, что это невозможно.Что этому мешает?Единственное, что этому мешает, это то, что незаконно помещать тигровую клетку в коллекцию клеток для животных.Клетка тигра не является своего рода клеткой для животных, потому что есть вещи, которые вы можете сделать с клеткой для животных, которые вы не можете сделать с клеткой для тигра, а именно, поместить в нее акулу.Основной принцип объектно-ориентированного проектирования заключается в том, что подтипы могут делать все, что могут делать их супертипы;клетка тигра не может делать все, что может делать клетка животного, поэтому она не является подтипом.
Более высокоуровневый способ сказать, что универсальные типы нельзя сделать ковариантными в своих аргументах типов, потому чтоэто нарушит принцип подстановки Лискова .В C # 4 определенные интерфейсы и делегаты являются ковариантными в своих аргументах типа.Например, в C # 4 разрешено помещать IEnumerable<Tiger>
в List<IEnumerable<Animal>>>
, потому что это невозможно сделать небезопасным.Мы можем придерживаться принципа подстановки, допуская ковариацию, поскольку IEnumerable<T>
является интерфейсом «только для использования».Вы только когда-либо убиваете тигров;туда нельзя посадить акул.