簡體   English   中英

C#中的多播委托怪異行為?

[英]Multicast delegate weird behavior in C#?

我有一個簡單的事件:

public class ClassA
{
    public event Func<string, int> Ev;
    public int Do(string l)
    {
        return Ev(l);
    }
}

和2方法:

  static int Display(string k)
        {
            return k.Length;
        }

  static int Display_2(string k)
        {
            return k.Length*10;
        }

我正在注冊此活動:

 ClassA a = new ClassA();
 a.Ev += Display;
 a.Ev += Display_2;

現在,我正在執行:

   Console.WriteLine(a.Do("aaa")); 

輸出 :

在此處輸入圖片說明

什么 ???

  • 他有調用列表2種方法! 確實運行了它們,但是為什么只顯示最后一次注冊的結果呢?

  • "3"的結果去哪里了? (第一次調用)? 盡管display + display_2被執行了...我沒想到console.write會遍歷結果。但是也沒想到他決定要顯示哪個。

編輯:

在此處輸入圖片說明

這里涉及三個方面:

  1. 活動的實施
  2. 委托組合的行為
  3. 調用其調用列表具有多個條目的委托的行為

對於點1,您有一個類似字段的事件。 C#4規范的10.8.1節給出了一個示例,並指出:

Button類的聲明之外, Click成員只能在+=-=運算符的左側saye上使用,如

 b.Click += new EventHandler(...); 

將委托附加到 Click事件的調用列表

(強調我的)。 該規范還明確指出,現場般的事件創建一個委托場,這是從類調用使用。

更一般地(第2點),C#4規范的7.8.4節討論了通過++=進行的委托組合:

委托組合。 每個委托類型都隱式提供以下預定義運算符,其中D是委托類型:

 D operator +(D x, D y) 

當兩個操作數均為某種委托類型D時,二進制+符執行委托組合。 [...跳過xy為null的位...]否則,操作的結果是一個新的委托,該委托在被調用時將調用第一個操作數,然后再調用第二個操作數

(再次強調我的意思。)

最后,要點3-事件調用和返回值。 C#規范的15.4節規定:

如果委托調用包括輸出參數或返回值,則它們的最終值將來自列表中最后一個委托的調用。

更一般而言,它取決於事件的實現。 如果您使用的事件實現使用“常規”委托組合/刪除步驟,則可以確保一切。 如果您開始編寫一個自定義的實現,它會做瘋狂的事情,那就大不一樣了。

調用多播非void委托將返回最后執行的處理程序的值。

您幾乎無法控制誰是第一名或最后一名。 它是一個糟糕的系統。

這就是為什么大多數事件和代表返回void

通常,事件返回值沒有意義。

如果要從事件處理程序中獲取信息,則使事件處理程序更改輸入參數更為有意義,或者只需調用觸發事件的任何對象的另一種方法來傳達其他信息即可。

通常情況下,甚至不會出現這種情況,因為事件在邏輯上將信息傳遞事件處理程序,並且不需要事件處理程序中獲取信息。 老實說,這是代碼氣味的跡象。 事件不必關心是否有人訂閱了該事件,他們可能是誰,他們可能在做什么,甚至是否有訂閱者。 依靠它們的返回值會造成過度緊密的耦合。

這些事件只是按照它們的附加順序進行迭代。 因為您使用的是返回值,所以獲取的值是最后一次調用的值。

不過,這實際上並不是事件的正常模式。 您可能想要一些類似的東西:

public class MyEventArgs : EventArgs
{
    public MyEventArgs()
    {
        Results = new List<int>();
    }
    public string InputString{get;set;}
    public List<int> Results{get;set;}
}
public event EventHandler<MyEventArgs> Ev
public int Do(string l)
{
    MyEventArgs e = new MyEventArgs();
    e.InputString = l;
    if(Ev != null) Ev(this, e);
    return e.Results.Sum();
}

接着

static int Display(object sender, MyEventArgs e)
        {
            return e.Results.Add(k.Length);
        }

  static int Display_2(object sender, MyEventArgs e)
        {
            return e.Results.Add(k.Length*10);
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM