首页 > 解决方案 > ArgumentException:向事件添加协变方法时委托类型不兼容

问题描述

尝试添加具有不同签名的两种方法时(彼此协变),我看到了非常奇怪的行为。ArgumentException: Incompatible Delegate Types当我尝试添加第二种方法时,它会抛出一个。

public class SomeClass { } // Just a class that inherits from object

public interface GenericInterface<out T> { // An interface with a covariant parameter T
    event System.Action<T> doSomethingWithT;
}

public interface SpecificInterface : GenericInterface<SomeClass> { } // A more specific interface where T = SomeClass

public class ImpClass: SpecificInterface {  // An implementation of the more specific interface
    public event System.Action<SomeClass> doSomethingWithT;
}

基本上是一个简单的泛型接口,其中泛型参数是协变的,一个为泛型分配类型的子接口,以及一个子接口的实现。

这是引发异常的代码:

protected void Start() {
    ImpClass impObj = new ImpClass();
    GenericInterface<object> genericObj = impObj; // assignment possible because interface is covariant

    impObj.doSomethingWithT += DoSomethingSpecific; 
    genericObj.doSomethingWithT += DoSomething; // this line throws an exception
}

protected void DoSomething(object o) { }
protected void DoSomethingSpecific(SomeClass o) { }

现在代码编译得很好,并且只添加更具体或更通用的方法,每个方法都可以单独工作,但如果我尝试同时添加两者,我会得到异常。

没有意义。知道为什么吗?以及任何解决方案?

标签: c#covariance

解决方案


至于可能的解决方案,您可以使用特定类型的引用来添加两个处理程序,并且由于协方差它可以正常工作:

impObj.doSomethingWithT += DoSomethingSpecific; 
impObj.doSomethingWithT += DoSomething; 

至于原因,我只能提供一个有根据的猜测:运行时将不允许将具有不同类型参数的处理程序附加到具有泛型类型的委托上,即使协变规则就编译器而言是有效的也是如此。并且泛型类型 () 的委托System.Action<T>正是您在使用genericObj引用时访问的内容,即使它在创建时已经使用具体的参数类型进行了初始化impObj


推荐阅读