0

我有这个简单的事件:

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会遍历结果。但也没想到他会决定显示哪个。

编辑 :

在此处输入图像描述

4

4 回答 4

7

这里有三个方面在起作用:

  1. 活动实施
  2. 委托组合行为
  3. 调用其调用列表具有多个条目的委托的行为

对于第 1 点,您有一个类似字段的事件。C# 4 规范的第 10.8.1 节给出了一个示例,并指出:

在类的声明之外Button,该Click成员只能用在+=and-=运算符的左侧,如

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

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

(强调我的)。该规范还明确指出,类字段事件创建一个委托字段,该字段类中用于调用。

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

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

D operator +(D x, D y)

当两个操作数都属于某种委托类型时,二元+运算符执行委托组合D。[...跳过xory为空的位 ...] 否则,操作的结果是一个新的委托,当被调用时,它会调用第一个操作数,然后调用第二个操作数

(再次强调我的。)

最后,第 3 点——事件调用和返回值。C# 规范的第 15.4 节指出:

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

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

于 2012-12-07T09:31:30.877 回答
4

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

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

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

于 2012-12-06T16:49:09.807 回答
4

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

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

这就是大多数事件和委托返回的原因void

于 2012-12-06T16:51:13.073 回答
3

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

不过,这并不是事件的正常模式。您可能想要更多类似的东西:

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);
        }
于 2012-12-06T16:58:21.127 回答