繁体   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