6

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

我收到“evtCheck(IntEvent)无法转换为Action<IFace>”的错误,即使IntEvent扩展了IFace接口。

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

4

2 回答 2

7

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

您不能从evtCheckto进行方法组转换,Action<IFace>因为它evtCheck需要一个比实例期望的更通用类型更具体的类型 ( ) 作为其参数。如果允许这样的转换,如果委托执行时使用了实现但不是 的参数,您会期望发生什么?IntEventIFaceAction<IFace>IFaceIntEvent

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

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

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

于 2012-06-10T16:09:29.567 回答
5

Action<T>在 T 中是逆变的,因此采用 an 的方法Action<T>也将接受Action<U>T 从 U 派生的地方。

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

强制性 Eric Lippert 参考资料:协变和逆变

编辑:根据您的描述,在我看来,您真正想要的是基于方法参数类型的差异化,因此,例如,您想要一个单独的操作用于IntEvent,另一个用于(假设的)DoubleEvent等。如果是这种情况,您实际上是双重虚拟分派后,C#中不直接支持,但可以使用访问者设计模式进行模拟。

于 2012-06-10T16:11:07.273 回答