Я думаю, что вы ищете ограничение общего типа :
interface IExecutor<T> where T : Command
{
void Execute(T command);
}
Это говорит о том, что T
может быть чем угодно, лишь бы оно расширяло класс Command
.
Ковариация в C # немного отличается от этого и касается преобразований между различными типами (массивами, обобщениями и делегатами).
Например, IEnumerable объявлен как IEnumerable<out T> { ... }
, что делает его ковариантным. Это обещание компилятору, что вы будете когда-либо только брать элементы из из IEnumerable<T>
и никогда не будете их вставлять.
Это означает, что писать безопасно, например,
IEnumerable<object> x = new List<string>();
Поскольку из IEnumerable
можно извлекать только строки, можно смело делать вид, что они все объекты. Если вам разрешено помещать предметы в IEnumerable
, то вы можете поместить любой старый объект в коллекцию, которая допускает только string
, что было бы небезопасно.
Возьмем ваш пример, потому что вы только когда-либо добавляете Commands
в IExecutor
, вы можете объявить его как контравариантный:
interface IExecutor<in T> where T : Command
{
void Execute(T command);
}
Это позволит вам написать:
IExecutor<Command> baseExecutor = ....;
IExecutor<SpecialisedCommand> executor = baseExecutor;
Это безопасно, потому что вы пообещали компилятору, что методы IExecutor
будут принимать только Command
объекты и никогда не будут их возвращать.