我使用以下示例来执行事件:
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
}
});
这是一个很好的方法吗?还是有更好的方法来处理带有异常的多线程事件?
答案 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是事件的另一个很好的选择。