如何委派正确的Action <Interface>?

tur*_*qel 6 .net c# delegates compiler-errors interface

我是C#的初学者,找不到任何答案:

我试图用一些接口参数委托动作,但推动使用扩展此接口(或类)的对象的函数

// some class extending interface
public class IntEvent : IFace{}
public class MoveEvent : IFace{}

// function i like to use to verify Action
static void setAction(Action<IFace> evt) {
    // evt ...
}
// function to delegate as Action
static void evtCheck(IntEvent evt) {
    // some func
}
static void evtMove(MoveEvent evt) {
    // some func
}
// class {
//  call method inside class and delegate this function :
setAction(evtCheck);
setAction(evtMove);
Run Code Online (Sandbox Code Playgroud)

即使扩展了界面,我也收到" evtCheck(IntEvent)无法转换为Action<IFace>" 的错误.IntEventIFace

我该怎么解决这个问题?也许我必须使用Func或Delegate?

Ani*_*Ani 7

你不能做你想做的事情 - 你期待协方差,但它的唯一类型参数Action<T>逆变的.

您不能进行方法组转换evtCheck,Action<IFace>因为evtCheck需要更具体的 type(IntEvent)作为其参数,而不是实例所期望的更通用的IFace类型Action<IFace>.如果允许这样的转换,如果委托是用一个实现IFace但不是一个的参数执行的话,你会发生IntEvent什么?

我认为你应该再看看你的设计,因为它看起来有一个缺陷,但如果你想,你可以创建一个lambda来强制将参数强制转换为所需的类型,并接受以下可能性InvalidCastException:

setAction(iFace => evtCheck((IntEvent)iface));
Run Code Online (Sandbox Code Playgroud)

更有可能的是,您可能希望evtCheck接受更通用的类型或setAction接受更具体的委托.


Ala*_*lan 5

Action<T>是T中的变量,因此采用的方法Action<T>也将接受Action<U>T源自U的情况。

IntEvent但是,您的类实现了该IFace接口,这意味着,如果编译器接受了您的setAction()调用,则可以evtCheck()使用另一个IFace-derivative而不是的参数进行调用,这是IntEvent运行时错误并且明显违反类型安全性。

必填的Eric Lippert参考:协方差和逆方差

编辑:根据您的描述,在我看来,您真正想要的是基于方法参数类型的区分,因此,例如,您想要针对IntEvent,针对(假设)DoubleEvent等的另一个动作。如果是这样,您实际上是在两次虚拟调度之后,C#不直接支持这种调度,但是您可以使用Visitor设计模式对其进行仿真。