如何委派正确的操作<界面>

本文关键字:操作 界面 何委派 委派 | 更新日期: 2023-09-27 18:36:39

我是 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);

我收到一个错误,即使IntEvent扩展了IFace接口,evtCheck(IntEvent)也无法转换为Action<IFace>"。

我应该如何解决这个问题?也许我必须使用 Func 或 Delegate ?

如何委派正确的操作<界面>

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

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

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

setAction(iFace => evtCheck((IntEvent)iface));

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

Action<T>在 T

中是逆变的,因此采用Action<T>的方法也将接受 T 派生自 U 的Action<U>

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

必修埃里克·利珀特参考:协方差和逆变

编辑:从您的描述来看,在我看来,您真正想要的是基于方法参数类型的区分,因此例如,您想要为IntEvent一个单独的操作,为(假设的)DoubleEvent等进行另一个操作。如果是这种情况,您实际上是在进行双重虚拟调度,这在 C# 中不直接受支持,但您可以使用 Visitor 设计模式对其进行模拟。