多播委托C#中的奇怪行为?

我有这个简单的事件:

public class ClassA { public event Func 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成员只能在+=-=运算符的左侧使用,如

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

它将委托附加到 Click事件的调用列表

(强调我的)。 该规范还清楚地表明,类似字段的事件会创建一个委托字段,该字段类中用于调用。

更一般地说(第2点),C#4规范第7.8.4节通过++=谈论委托组合:

代表组合。 每个委托类型隐式提供以下预定义运算符,其中D是委托类型:

 D operator +(D x, D y) 

当两个操作数都是某个委托类型D时,binary + operato执行委托组合。 […跳过xy为空的位…]否则,操作的结果是一个新的委托,当被调用时, 调用第一个操作数然后调用第二个操作数

(再一次,强调我的。)

最后,第3点 – 事件调用和返回值。 C#规范第15.4节规定:

如果委托调用包括输出参数或返回值,则它们的最终值将来自列表中最后一个委托的调用。

更一般地说,它取决于事件的实现。 如果您使用使用“正常”委托组合/删除步骤的事件实现,则一切都得到保证。 如果你开始编写一个做疯狂事情的​​自定义实现,那就不一样了。

调用多播非void委托会返回已执行的最后一个处理程序的值。

你几乎无法控制谁是第一个或最后一个。 这是一个糟糕的系统使用。

这就是大多数事件和代表返回void

作为一般规则,事件返回值没有意义。

如果你想从事件处理程序获取信息,那么事件处理程序改变输入参数更有意义,或者只是调用触发事件的任何对象的另一个方法来传递其他信息。

通常,这甚至不会出现,因为事件在逻辑上将信息传递事件处理程序,并且不需要事件处理程序获取信息。 它老实说是代码味道的标志。 事件不应该关心是否有人订阅了它,他们可能是谁,他们可能在做什么,或者即使有任何订阅者。 依赖于它们的返回值然后只是创建过度紧密的耦合。

事件只是按照它们附加的顺序迭代。 因为您使用的是返回值,所以您获得的值是最后一次调用的值。

事实上,这不是一个真正的事件模式。 你可能想要更多的东西:

 public class MyEventArgs : EventArgs { public MyEventArgs() { Results = new List(); } public string InputString{get;set;} public List Results{get;set;} } public event EventHandler 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); }