我刚刚将我的主应用程序从.NET 2.0升级到.NET 4.5,并且我试图利用C#5.0提供的更高级的语言功能。
我目前正在重新编写一些旧的异步代码例程,这些例程使用" MethodInvoker" /" AsyncCallback" (以保持UI流畅)任务。
以下是旧代码遵循的模式......
void RefreshScreen()
{
// code to prepare UI for updating
...
MethodInvoker del = new MethodInvoker(LoadData);
del.BeginInvoke(new AsyncCallback(LoadData_Callback), null);
}
void LoadData()
{
// perform data calculations
}
void LoadData_Callback(IAsyncResult ar)
{
AsyncResult res = (System.Runtime.Remoting.Messaging.AsyncResult)ar;
MethodInvoker del = (MethodInvoker)res.AsyncDelegate;
try
{
del.EndInvoke(ar); // <- throw exception if one occurred during async operation
}
catch (Exception E)
{
// handle exception
}
// Update the UI: if (this.InvokeRequired) {...}
}
好的 - 所以我到目前为止的基于任务的等价物: -
void RefreshScreen()
{
// code to prepare UI for updating
...
Task.Run(() => LoadData()).ContinueWith((t) => LoadData_Callback(t));
}
void LoadData()
{
// perform data calculations
}
void LoadData_Callback(Task t)
{
try
{
t.Wait(); // <- throw exception if one occurred during async operation
}
catch (Exception E)
{
// handle exception
}
// Update the UI: if (this.InvokeRequired) {...}
}
所以这里是我的问题......我已经阅读了很多关于使用任务进行异常处理的文章和资源,其中一些人讨论了检查&#34; task.IsCompleted等问题。 &#34;和/或&#34; task.Status &#34;,并使用 TaskContinuationOptions 分支到多个 ContinueWiths 。
我试图让它尽可能简单,所以只需拨打&#34; task.Wait()&#34;在一个ContinueWith方法中,在那里捕获一个Exception(根据上面的代码)还是有更好的方法来做到这一点?
非常感谢!
更新和答案
为了澄清,我应该解释原始代码在WinForms应用程序中使用,目标是在长DB操作(或任何其他长进程)期间保持UI响应,通过异步运行它们一个不同的主题。
Silas和Servy指出,自从切换到C#5.0后,我应该使用 async / 等待,所以这是我选择使用的代码类似于上面的例子......
async Task RefreshScreen()
{
// code to prepare UI for updating
...
try
{
await Task.Run(() => LoadData());
}
catch (Exception E)
{
// handle exception
}
// Update the UI: WITHOUT the need to check "this.InvokeRequired"
return Task.FromResult(0);
}
Task LoadData()
{
// perform data calculations
return Task.FromResult(0);
}
此代码至少有两个好处超过&#34; MethodInvoker &#34;或&#34; 任务&#34;方法: -
(1)它更清楚了
(2)Ater从 await 返回,后续代码在UI线程上,所以没有必要用&#34; if(this.InvokeRequired){ ...} &#34; (see Stephen Cleary's blog for more information on this)。
原始问题怎么样? 是否可以使用Wait来捕获ContinueWith中的异常?
我认为这是一个没有实际意义的问题,因为 async / await 显然是要走的路,但经过进一步的研究,答案是肯定的。&#39;没问题!
答案 0 :(得分:5)
您可以用以下内容替换所有内容:
public async Task LoadData()
{
// do something DB intensive
}
public async Task HandleLoadExceptions()
{
try
{
await LoadData();
}
catch (Exception E)
{
// handle exception
}
}