C# BackgroundWorker.RunWorkCompleted-无法重试异常
我正在为WCF调用编写某种包装(使用BackgroundWorker),以防止调用进行时GUI冻结。它基本上正常工作,但当WCF调用引发异常时,我与BackgroundWorker有一个问题。如果DoWork中发生异常,我可以在RunWorkCompleted中检测到它,但将其重新提交到GUI不起作用。我读过很多文章,有人提到这应该是可行的 包装器的代码(请注意,WCF调用由抛出的异常表示): 调试时,我得到:C# BackgroundWorker.RunWorkCompleted-无法重试异常,c#,exception,backgroundworker,C#,Exception,Backgroundworker,我正在为WCF调用编写某种包装(使用BackgroundWorker),以防止调用进行时GUI冻结。它基本上正常工作,但当WCF调用引发异常时,我与BackgroundWorker有一个问题。如果DoWork中发生异常,我可以在RunWorkCompleted中检测到它,但将其重新提交到GUI不起作用。我读过很多文章,有人提到这应该是可行的 包装器的代码(请注意,WCF调用由抛出的异常表示): 调试时,我得到: DoWork中引发了“System.Exception”类型的异常 在抛出evt.E
我做错了什么?我想在Windows窗体中捕获异常。事件
b.RunWorkerCompleted
是您应该执行错误处理的地方。您可以传入一个操作
,以执行如下错误处理
private void GetSomething(Action<IEnumerable<int>> completedAction, Action<Exception> exceptionAction)
{
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)
exceptionAction(evt.Error);
};
b.RunWorkerAsync();
}
如果您使用.Net 4.5和C#5(您需要VS2012或VS2010以及异步CTP),您甚至可以求助于Async
和wait
等
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
。您应该更改此选项:
抛出evt.Error代码>
为此:
MessageBox.Show(evt.Error.Message)代码>
您的异常当前未处理,因为RunWorkerCompleted
处理程序稍后正在运行。它没有在您在按钮3\u Click
中的try/catch中运行。您应该在RunWorkerCompleted中处理异常。是否有任何特定的原因让您重试。@CodeIgnoto:我的想法是将此决定推给调用方。我不想使用消息框,比如说,从这个包装。根据我的经验,任何在RunWorkerCompleted代码中抛出的异常都会导致应用程序停止运行。所以,去完成任务或者在那里处理它。如果您在启动时使用while(true)Application.DoEvents()而不是Application.Run(),则可以对DoEvents执行try catch,它将捕获您刚刚重试的异常。但是有些代码可能不会像预期的那样使用这种“消息”循环运行。我现在试过了。第一个问题是“foreach(列表中的inti)”不会编译,因为GetSomething的返回类型是一个任务。将其更改为迭代task.Result后,我的GUI在调用过程中被阻止,并且未捕获异常。抱歉。你完全正确。带有ContinueWith
的示例毫无意义。我纠正了它。但是,如果使用Task.Factory.StartNew()
,则不应阻止GUI。我将尝试此操作,谢谢。事实上,我认为你的第一个解决方案是通过一个动作。这将从GUI中抽象出许多细节。
private void GetSomething(Action<IEnumerable<int>> completedAction, Action<Exception> exceptionAction)
{
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)
exceptionAction(evt.Error);
};
b.RunWorkerAsync();
}
Task<IEnumerable<int>> GetSomething()
{
return Task.Factory.StartNew(() => {
Thread.Sleep(2000);
throw new Exception();
return (new List<int> { 1, 2, 3 }).AsEnumerable();
});
}
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()));
}
}
});
}
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);
}
}