我正在为WCF调用(使用BackgroundWorker)编写某种包装器,以便在调用正在进行时保持GUI不冻结.它主要是按预期工作,但是当WCF调用抛出异常时,我遇到了BackgroundWorker的问题.如果在DoWork中发生异常,我可以在RunWorkCompleted中检测到它,但是将其重新抛出到GUI不起作用.我已经读了很多线程,人们提到这应该有效.
private void GetSomething(Action<IEnumerable<int>> completedAction) { BackgroundWorker b = new BackgroundWorker(); b.DoWork += (s,evt) => { throw new Exception(); evt.Result = new List<int> { 1,2,3 }; }; b.RunWorkerCompleted += (s,evt) => { if (evt.Error == null && completedAction != null) { completedAction((IEnumerable<int>)evt.Result); } else if(evt.Error != null) { throw evt.Error; } }; b.RunWorkerAsync(); }
private void button3_Click(object sender,EventArgs e) { try { GetSomething(list => { foreach (int i in list) { listView1.Items.Add(new ListViewItem(i.ToString())); } }); } catch (Exception ex) { MessageBox.Show(ex.Message); } }
在调试时,我得到:
我究竟做错了什么?我想在Windows窗体中捕获异常.
解决方法
事件b.RunWorkerCompleted是您应该进行错误处理的地方.您可以传递一个Action< Exception>做错误处理就像
private void GetSomething(Action<IEnumerable<int>> completedAction,Action<Exception> exceptionAction) { BackgroundWorker b = new BackgroundWorker(); b.DoWork += (s,evt) => { if (evt.Error == null && completedAction != null) completedAction((IEnumerable<int>)evt.Result); else if(evt.Error != null) exceptionAction(evt.Error); }; b.RunWorkerAsync(); }
然而,这往往会变得丑陋.如果您使用.Net 4或4.5,则可以使用“任务”.任务< TResult>是为了这种情况而创建的:
Task<IEnumerable<int>> GetSomething() { return Task.Factory.StartNew(() => { Thread.Sleep(2000); throw new Exception(); return (new List<int> { 1,3 }).AsEnumerable(); }); }
任务基本上是一个信号构造
> a.结果财产
> .Exception属性
> a .ContinueWith()方法
在ContinueWith()中,您可以检查Task是否处于故障状态(Exception被抛出).
你可以像使用它一样
private void button3_Click(object sender,EventArgs e) { GetSomething() .ContinueWith(task => { if (task.IsCanceled) { } else if (task.IsFaulted) { var ex = task.Exception.InnerException; MessageBox.Show(ex.Message); } else if (task.IsCompleted) { var list = task.Result; foreach (int i in list) { listView1.Items.Add(new ListViewItem(i.ToString())); } } }); }
如果您使用.Net 4.5和C#5(您需要VS2012或VS2010和Async CTP),您甚至可以使用异步并等待
private async void button3_Click(object sender,EventArgs e) { try { var list = await GetSomething(); foreach (int i in list) { listView1.Items.Add(new ListViewItem(i.ToString())); } } catch (Exception ex) { MessageBox.Show(ex.Message); } }
……所有的魔力都是由编译器完成的.请注意,您可以像以前一样使用try catch.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。