7

私は次のEventHandlerを持っています:

private EventHandler<MyEventArgs> _myEventHandler;
public event EventHandler<MyEventArgs> MyEvent
{
  add { _myEventHandler += value; }
  remove { _myEventHandler -= value; }
}  

次のスニペットの違いを誰かが説明できますか?
Snippet EventHandler(A):

//Snippet A:
if (_myEventHandler != null)
{
  _myEventHandler(new MyEventArgs());
}

Snippet BeginInvoke(B):

//Snippet B:
if (_myEventHandler != null)
{
  _myEventHandler.BeginInvoke(new MyEventArgs(), ar =>
  {
    var del = (EventHandler<MyEventArgs>)ar.AsyncState;
    del.EndInvoke(ar);
  }, _myEventHandler);
}

明確にするために:「そのまま」EventHandlerを呼び出すことと使用することの違いは何BeginInvokeですか?

4

2 に答える 2

15

The BeginInvoke approach is async, meaning that it is raised on a different thread. This can be dangerous if people don't expect it, and is pretty rare for events - but it can be useful.

Also, note that strictly speaking you should snapshot the event handler value - this is especially true if (via Begin*) you are dealing with threads.

var tmp = _myEventHandler;
if(tmp != null) {
    tmp(sender, args);
}

Also - note that your event subscription itself is not thread-safe; again, this only matters if you are dealing with multi-threading, but the inbuilt field-like event is thread-safe:

public event EventHandler<MyEventArgs> MyEvent; // <===== done; nothing more

The issues avoided here are:

  • with the snapshot, we avoid the risk of the last subscriber unsubscribing between the null-check and the invoke (it does mean they might get an event they didn't expect, but it means we don't kill the raising thread)
  • with the field-like event change we avoid the risk of losing subscriptions / unsubscriptions when two threads are doing this at the same time
于 2011-08-11T09:37:04.107 に答える
5

BeginInvoke()call はすぐに制御を呼び出し元のスレッドに戻し、デリゲートを とは別のスレッドで実行するThreadPoolため、これはある種の非同期実行になります。

于 2011-08-11T09:43:33.107 に答える