Threadsafe和异常捕获事件

时间:2014-07-04 10:05:25

标签: c# events

我使用以下示例来执行事件:

try
{
    if (this.onClientConnected != null)
        this.onClientConnected(this, new EventArgs());
}
catch (Exception e)
{
    //log and handle exception
}

但是当然这有一些缺点,比如如果一个订阅的委托抛出一个异常,其余部分不会被执行,因为我在多线程应用程序中使用它来检查null并抛出某个人可以取消订阅的事件并抛出一个null异常

现在我看了一个更好的方法来抛出这些事件并提出这个:

Delegate[] methods = this.onClientConnected.GetInvocationList();
methods.ToList().ForEach(x =>
{
    try
    {
        x.DynamicInvoke(this, new EventReceivedEventArgs(Trigger.TriggerName, Trigger.InstanceID, Trigger.Parameters, Trigger.SourceIpAddress));
    }
    catch (Exception e)
    {
        //log and handle exception
    }
});

这是一个很好的方法吗?还是有更好的方法来处理带有异常的多线程事件?

1 个答案:

答案 0 :(得分:0)

是否可以通过从同一个线程运行所有添加/删除属性访问,或者在正确的抽象级别使用锁来序列化所有订阅/取消订阅逻辑?请参阅Stephen Toub's discussion on this topic

我会将多播委托从事件中缓存到一个局部变量中,检查它,然后“调用”它。见Eric Lippert's discussion on the topic.

考虑将任务中的事件包装为Igor Ostrovsky describes in this MSDN Article。这是TPL路线......

例如(我在引用):

static Task<string> DownloadStringAsTask(Uri address) {
  TaskCompletionSource<string> tcs = 
    new TaskCompletionSource<string>();
  WebClient client = new WebClient();
  client.DownloadStringCompleted += (sender, args) => {
    if (args.Error != null) tcs.SetException(args.Error);
    else if (args.Cancelled) tcs.SetCanceled();
    else tcs.SetResult(args.Result);
  };
  client.DownloadStringAsync(address);
  return tcs.Task;
}

在评估返回的任务的任何地方都可以观察到异常,例如使用.Result或.Wait()。

考虑通过同一个线程汇总事件处理。例如,使用.ContinueWith()重载,它会占用始终发布到UI线程的调度程序。

最后,Rx是事件的另一个很好的选择。