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 它们。
我一直在努力弄清楚如何在 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 它们。