Проблема в том, что если то, что вы хотите, было законным, то это также было бы законно:
abstract class Animal {}
class Goldfish : Animal {}
class Giraffe : Animal {}
abstract class Cage<T> where T : Animal {
void Add(T newAnimal) { ... }
}
class Aquarium : Cage<Goldfish> { }
...
Cage<Animal> c = new Aquarium(); // This is not legal, but suppose it was
c.Add(new Giraffe()); // A giraffe is an animal
А теперь у нас в аквариуме жираф, который никого не радует.
Эта функция называется ковариация , и она работает только на универсальном интерфейсе и делегатах , когда они построены с ссылочными типами , и они разработан специально для обработки отклонений и проверен на безопасность компилятором .
Например, вы можете использовать IEnumerable<Fish>
в контексте, где ожидается IEnumerable<Animal>
, потому что нет никакого способа добавить жирафа в последовательность животных.
Разве я не могу иметь универсальный тип, производный от базового класса, и все еще использовать его?
Да, но вы должны следовать правилам. Эти правила предназначены для вашей безопасности . Узнайте, как работает система типов и как с ней работать, чтобы предотвратить появление ошибок, и вы никогда не по ошибке поместите жирафа в аквариум.