2

I was recently asked a question what will happen if I would query one handler twice. Let me just show you code:

 public delegate void OpenEventHandler(object sender, EventArgs e);

 public class MyWindow
 {
     public event OpenEventHandler Open;

     public void OpenWindow()
     {
         if (Open != null)
         {
             Open(this, new EventArgs());
         }
     }
 }

 public class TwoDelegates
 {
     public static void HandleOpen(Object sender, EventArgs e)
     {
         Console.WriteLine("Birds fly");
         (sender as MyWindow).Open -= HandleOpen;
     }

     public static void Run()
     {
         var window = new MyWindow();
         window.Open += HandleOpen;
         window.Open += HandleOpen;

         window.OpenWindow();
         Console.ReadKey();
     }
 }

I wonder why string is still printed twice. On the beginning of it Invocation list consist of two items with same delegate reference, but after a first run it is cleaned up, still the secon invocaiton appears.

Update1:

Seems that even simple -= removes only one entry:

 var window = new MyWindow();

 window.Open += HandleOpen;
 window.Open += HandleOpen;

 Console.WriteLine(window.getHandlers().Count());
 window.Open -= HandleOpen;
 Console.WriteLine(window.getHandlers().Count());

Though debug mode in VS2010, while you look through window.Open internal properties shows empty invocation list with 0 count. Seems that it's some magic in debug info displayed in VS.

4

2 回答 2

1

这是委托如何触发事件处理程序的问题。它在开始触发之前获取内部委托列表的副本。因此,为同一事件的事件处理程序内部的事件添加或删除事件处理程序只会影响该事件的未来调用,而不影响当前调用。

于 2013-04-24T15:43:08.237 回答
1

为了扩展 Servy 所说的内容,这里有一个稍微修改过的代码版本,并带有一些调试助手来澄清发生了什么。在 HandleOpen 函数中,我们检查从事件中删除 HandleOpen 前后的事件处理程序。总结是:在您的多播中有两个 HandleOpen 副本,单个 Open-=HandleOpen 没有理由同时删除它们。

public class MyWindow
{
    public event OpenEventHandler Open;

    public void OpenWindow()
    {
        if (Open != null)
        {
            Open(this, new EventArgs());
        }
    }

    public Delegate[] getHandlers()
    {
        return Open.GetInvocationList();
    }
}

public class TwoDelegates
{
    public static void HandleOpen(Object sender, EventArgs e)
    {
        Console.WriteLine("Birds fly");
        var thisWin = sender as MyWindow;
        var before = thisWin.getHandlers();

        (sender as MyWindow).Open -= HandleOpen;
        var after = thisWin.getHandlers();

    }

    public static void Run()
    {
        var window = new MyWindow();
        window.Open += HandleOpen;
        window.Open += HandleOpen;

        window.OpenWindow();
        Console.ReadKey();
    }
}
于 2013-04-24T16:06:41.653 回答