C# 动作代理的协方差和逆变

C# 动作代理的协方差和逆变,c#,C#,我被卡住了,为什么这不起作用: var childAction = new Action<CancelCommand>(blabla); Action<IDomainCommand> upperAction = (Action<IDomainCommand>) childAction; var childAction=新操作(blabla); Action upperAction=(Action)childAction; 如果CancelComma

我被卡住了,为什么这不起作用:

  var childAction = new Action<CancelCommand>(blabla);
  Action<IDomainCommand> upperAction = (Action<IDomainCommand>) childAction;
var childAction=新操作(blabla);
Action upperAction=(Action)childAction;
如果CancelCommand实现IDOMAIN命令,为什么不起作用? 顺便问一下:我在这里想做的是协变还是逆变

先谢谢你 最好的 劳林

编辑 谢谢你们的快速回复

我之所以需要它,是因为我构造了一个通用的操作模板。 我有以下界面:

IMessageBus.RegisterAction<T>(Action<T> registerAction) where T : IDomainCommand
IMessageBus.RegisterAction(Action RegisterAction),其中T:IDOMain命令
因为我必须在运行时构建此操作,所以我的代码如下所示:

var genericExecuteAction = this.GetType().GetMethod("ExecuteCommandAction",
                                                            BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(commandType);

var actionType = typeof(Action<>).MakeGenericType(commandType);
var @delegate = Delegate.CreateDelegate(actionType, this, genericExecuteAction);
var actionDelegate = (Action<DomainCommandBase>)@delegate;

messageBus.Register(actionDelegate);
var genericExecuteAction=this.GetType().GetMethod(“ExecuteCommandAction”,
BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(commandType);
var actionType=typeof(Action).MakeGenericType(commandType);
var@delegate=delegate.CreateDelegate(actionType,this,genericExecuteAction);
var actionDelegate=(Action)@delegate;
messageBus.Register(actionDelegate);
问题是我需要强制转换它,以便将其传递给此方法。 看到了吗?
我们使用的mesasge总线背后是RX,不幸的是,所有的方法都使用泛型,现在出现了非泛型重载。

Action的类型参数是反变的:您可以将
Action
分配给
Action
,因为显然可以处理任何对象的方法也可以处理字符串


您在这里所做的是尝试将在
CancelCommand
(派生类型)上工作的方法作为在任何
IDomainCommand
(基本类型)上工作的方法计费。这在逻辑上是错误的,因此编译器不允许您这样做——如果它允许,您可以调用
upperAction
向其传递
不同类型的域命令
,这是相反的。这不起作用,因为如果可能的话,您可以这样写:

interface IDomainCommand { }
class CancelCommand : IDomainCommand { }
class AcceptCommand : IDomainCommand { }

        Action<CancelCommand> a1 = c => { };
        Action<IDomainCommand> a2 = a1;

        var acceptCommand = new AcceptCommand();

        a2(acceptCommand); // what???
接口IDOMAIN命令{}
类CancelCommand:IDomainCommand{}
类AcceptCommand:IDomainCommand{}
动作a1=c=>{};
动作a2=a1;
var acceptCommand=new acceptCommand();
a2(接受命令);//什么???

a2
指向
a1
,a1不能接受
AcceptCommand
参数,因为它不是
CancelCommand
等等,为什么要这样做

您的
childAction
是一种接受
CancelCommand
并对其执行操作的功能

但是
upperAction
可以在任何
idomain命令
上调用,而不仅仅是
取消命令
。假设上述条件成立;当我这样做的时候会发生什么

upperAction(new EditCommand());
其中
类EditCommand:IDomainCommand

如果您尝试以另一种方式分配任务:

        var upperAction = new Action<IDomainCommand>(idc => { });
        Action<CancelCommand> childAction = upperAction;
var upperAction=新操作(idc=>{});
Action childAction=upperAction;

它很有效,你甚至不需要演员阵容。任何
操作
都算作
操作

您忘记了如何使用这些代理

var childAction = new Action<CancelCommand>(blabla);
Action<IDomainCommand> upperAction = (Action<IDomainCommand>) childAction;
var childAction=新操作(blabla);
Action upperAction=(Action)childAction;

意味着
upperAction
将在将来的某个时候被调用,传递某种形式的
IDomainCommand
对象。您赋予它一个只能处理
CancelCommand
对象的函数。但是(可能)还有其他类实现了
IDomainCommand
,并且
upperAction
可以与它们中的任何一个一起调用。

Co-&Contra-variance只在接口上起作用,不是委托。@Enigmativity:它也适用于委托。谢谢。我找到了答案:我只需要调用Register方法over reflection=)谢谢你们的快速回答。我通过编辑我的初始问题来回答你的问题。