线程安全和异常捕获事件

本文关键字:事件 异常 安全 线程 | 更新日期: 2023-09-27 18:11:21

我使用了下面的例子来执行事件:

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
    }
});

这是一个好方法,或者有一个更好的方法来处理多线程事件与异常?

线程安全和异常捕获事件

是否可以通过在同一线程中运行所有的add/remove属性访问,或者在正确的抽象级别上使用锁来序列化所有的订阅/取消订阅逻辑?请看Stephen Toub关于这个话题的讨论。

我将把事件中的多播委托缓存到一个局部变量中,检查它,然后"调用"它。参见Eric Lippert对该主题的讨论。

考虑在任务中包装事件,正如Igor Ostrovsky在MSDN文章中所描述的那样。这是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;
}

在计算返回的Task的任何地方都可以观察到异常,例如使用。result或。wait()。

考虑通过同一线程进行事件处理。例如,使用. continuewith()重载,它接受一个调度程序,该调度程序总是向UI线程发送消息。

最后,Rx是事件的另一个很好的替代方案。