亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

ArgumentException:向事件添加協變方法時出現不兼容的委托類型

ArgumentException:向事件添加協變方法時出現不兼容的委托類型

C#
慕雪6442864 2023-08-13 09:42:29
當嘗試添加具有不同簽名的兩種方法(彼此是協變的)時,我看到非常奇怪的行為。ArgumentException: Incompatible Delegate Types當我嘗試添加第二種方法時,它會拋出一個異常。public class SomeClass { } // Just a class that inherits from objectpublic 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 = SomeClasspublic 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) { }現在代碼可以正常編譯,并且僅添加更具體的方法或僅添加更通用的方法,每個方法都可以單獨正常工作,但如果我嘗試添加兩者,則會出現異常。沒有道理。知道為什么嗎?以及有什么解決辦法嗎?
查看完整描述

2 回答

?
慕姐8265434

TA貢獻1813條經驗 獲得超2個贊

至于可能的解決方案,您可以使用特定類型的引用來添加兩個處理程序,并且由于協方差,它可以正常工作:

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

至于原因,我只能提供一個有根據的猜測:運行時不允許將具有不同類型參數的處理程序附加到具有泛型類型的委托,即使協方差規則對于編譯器而言是有效的。泛型類型 ( System.Action<T>) 的委托正是您在使用genericObj引用時所訪問的對象,即使它在創建 時已使用具體參數類型進行了初始化impObj。


查看完整回答
反對 回復 2023-08-13
?
滄海一幻覺

TA貢獻1824條經驗 獲得超5個贊

我仍然沒有找到為什么會發生這種情況的解釋,但我確實找到了一種解決方法,可以讓您做到這一點。您必須實現事件的訪問器并將委托保存在單獨的列表或哈希集中,而不是使用內置事件實現。


public class ImpClass: SpecificInterface {  // An implementation of the more specific interface

    public event System.Action<SomeClass> doSomethingWithT { 

        add { delegateSubs.Add(value); } 

        remove { delegateSubs.Remove(value); } 

    }


    protected HashSet<System.Action<SomeClass>> delegateSubs = new HashSet<System.Action<SomeClass>>();

}

這樣您就可以毫無問題地添加/刪除 T 的多個基本類型的委托。當然,缺點是您必須為每個實現該接口的類執行此操作,但它保證每當您使用這些類的事件時,無論 T 如何,它都會起作用并且不會引發異常。


查看完整回答
反對 回復 2023-08-13
  • 2 回答
  • 0 關注
  • 200 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號