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

C# C中的多播委托奇怪行为?,c#,.net,delegates,C#,.net,Delegates,我有一个简单的事件: public class ClassA { public event Func<string, int> Ev; public int Do(string l) { return Ev(l); } } 我正在注册此活动: ClassA a = new ClassA(); a.Ev += Display; a.Ev += Display_2; 现在,我正在执行: Console.WriteLine(a

我有一个简单的事件:

public class ClassA
{
    public event Func<string, int> Ev;
    public int Do(string l)
    {
        return Ev(l);
    }
}
我正在注册此活动:

 ClassA a = new ClassA();
 a.Ev += Display;
 a.Ev += Display_2;
现在,我正在执行:

   Console.WriteLine(a.Do("aaa")); 
输出:

什么

他在调用列表中列出了2种方法!它确实运行了它们,但为什么只显示上次注册的结果

3的结果到哪里去了?第一次调用?虽然显示+显示2都已执行。。。我没想到console.write会遍历结果。但也没想到他会决定展示哪个

编辑:
一般来说,事件返回值是没有意义的

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


通常情况下,这甚至不会出现,因为事件在逻辑上将信息传递给事件处理程序,并且不需要从事件处理程序获取信息。老实说,这是代码气味的迹象。事件不应该关心是否有人订阅了它,他们可能是谁,他们可能在做什么,甚至是否有订阅者。依赖它们的返回值只会造成过度紧密的耦合。

调用多播非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();
}

这里有三个方面:

活动的实施 委托组合的行为 调用其调用列表具有多个条目的委托的行为 对于第1点,您有一个类似于字段的事件。C4规范第10.8.1节给出了一个示例,并说明:

在Button类的声明之外,Click成员只能在+=和-=运算符的左侧saide上使用,如中所示

b.Click += new EventHandler(...);
将委托追加到单击事件的调用列表

我的。该规范还明确指出,类似字段的事件会创建一个委托字段,该字段在类内用于调用

更一般地说,C4规范第7.8.4节第2点讨论了通过+和+=”组合委托:

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

D operator +(D x, D y)
当两个操作数都是某种委托类型D时,二进制+运算符执行委托组合。[…跳过x或y为空的位…]否则,操作的结果是一个新委托,在调用时,该委托调用第一个操作数,然后调用第二个操作数

再次强调我的

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

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


更一般地说,它取决于事件实现。如果您使用使用普通委托组合/删除步骤的事件实现,那么一切都是有保证的。如果您开始编写一个做了疯狂事情的自定义实现,那就不一样了。

这里没有委托数组。它是某种集合。您可以将其作为数组获取,但您的代码不能。只是一个选择更好标题的提示。它被称为多播委托,而不是委托数组。@RoyiNamir它怎么能全部返回它们呢?它的类型不适合它返回所有的字符,它需要某种类型的集合才能返回,然后它就不会匹配它自己的签名了。@RoyiNamir是的,你没想到它会这样做,我明白了。我问的是你期望它做什么,而不是你不期望它做什么。如何回答我的问题:为什么只显示一个值?为什么他决定哪一个是可见的?@RoyiNamir它将始终返回列表中最后一个委托的值,但我的观点是,你不应该一开始就依赖它。它不在C语言规范中,它是一个实现细节。它在C或CLR规范中。但事实上,永远不要依赖它。@Servy知道调用列表是否在执行对我来说非常重要。不是世界上所有的人都是一样的。你对谁是第一个或最后一个几乎没有控制权?它们的附加方式-这将是订单号?首先是。但是,在删除并添加了一些处理程序之后,很难预测,甚至可能是实现定义的。我不确定是否可以。我相信你甚至不应该尝试。您可以创建一个管理y
如果您真的需要,我们自己的委托列表。@Servy-每个事件都使用一个多播委托。对于类似于事件的字段,将按订阅顺序调用委托-这都是定义良好的。对于一个更一般的事件,情况当然不是这样-不能保证一个事件会提供合理的添加/删除实现。。。但我会非常惊讶地看到一个没有。当然,在C语言中,调用并不是处理事件的一部分……这不是Henk说的。@RoyiNamir怎么会这样?我看不出两者之间有矛盾。他说,调用顺序可能与附加的顺序不同
b.Click += new EventHandler(...);
D operator +(D x, D y)