C#接口协方差,指定参数类型

时间:2019-05-24 12:04:26

标签: java c# covariance

我一直在尝试找出如何在C#中获得以下Java代码的等效项(命令是功能接口)。

public interface Executor<C extends Command> {
    void execute(final C command) throws Exception;
}

我目前在Java版本中设计代码的方式,类型C扩展Command是必要的,据我所知,Command是用C#的协方差来处理的。

但是根据C#文档,由于“ The type is used only as a return type of interface methods and not used as a type of method arguments”之类的以下内容将不起作用

interface IExecutor<out Command>
{
    void Execute(Command command);
}

是否有一种方法可以指定方法的参数类型必须与C#中的接口类型协变量?

我是C#的新手,所以可能是XY问题,但到目前为止我还没有找到可行的解决方案。

1 个答案:

答案 0 :(得分:2)

我认为您追求的是generic type constraint

interface IExecutor<T> where T : Command
{
    void Execute(T command);
}

这表示T可以是任何东西,只要它扩展了Command类。

C#中的

Covariance与此有点不同,它涉及不同类型(数组,泛型和委托)之间的转换。

例如,IEnumerable声明为IEnumerable<out T> { ... },这使其成为协变变量。这是对编译器的保证,即您将永远只提取IEnumerable<T>中的项目 out ,而永远不会将它们放入。

这意味着可以安全地编写例如

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对象,并且永远不会返回它们。