c# - 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) { }
现在代码编译得很好,并且只添加更具体或更通用的方法,每个方法都可以单独工作,但如果我尝试同时添加两者,我会得到异常。
没有意义。知道为什么吗?以及任何解决方案?
解决方案
至于可能的解决方案,您可以使用特定类型的引用来添加两个处理程序,并且由于协方差它可以正常工作:
impObj.doSomethingWithT += DoSomethingSpecific;
impObj.doSomethingWithT += DoSomething;
至于原因,我只能提供一个有根据的猜测:运行时将不允许将具有不同类型参数的处理程序附加到具有泛型类型的委托上,即使协变规则就编译器而言是有效的也是如此。并且泛型类型 () 的委托System.Action<T>
正是您在使用genericObj
引用时访问的内容,即使它在创建时已经使用具体的参数类型进行了初始化impObj
。
推荐阅读
- reactjs - 使用函数作为 useEffect 依赖项->“缺少依赖项'props'”
- python - Python - 如何访问从 S3 下载的文件以重新上传
- c# - 你能用 AOT/CoreRT 在 .NET Core 3.0 上编译复杂的 WinForms 应用吗?
- javascript - 将 ID 标签添加到父级
- ruby-on-rails - 安全过滤 Active Storage 文件名?
- bash - 为什么需要 2 个反斜杠来转义 vim -c 参数中的反斜杠?
- laravel - Laravel 护照;将 OAuth2 与 Freshdesk 一起用于 SSO
- java - Mapstruct - 从源对象的一组字段中准备一个列表并将其设置为目标对象
- html - 无需使用 v-html 即可显示 markdown
- javascript - base.html 文件结构末尾的 Django JavaScript 标记