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

C# interface covariance, specify parameter type

我一直在努力弄清楚如何在 C# 中获得与以下 Java 代码等效的代码(命令是函数式接口)。

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

我的代码目前在Java版本中的设计方式,C类型需要扩展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 问题,但到目前为止我还没有找到可行的解决方案。

我想你想要的是 generic type constraint:

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

这表示 T 可以是任何东西,只要它扩展 Command class.

Covariance 在 C# 中与此有点不同,它是关于不同类型(数组、泛型和委托)之间的转换。

例如,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 个对象,并且永远不会 return 它们。