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)