【发布时间】:2017-02-24 18:47:10
【问题描述】:
我刚刚将我的主应用程序从 .NET 2.0 升级到 .NET 4.5,我正在尝试利用 C# 5.0 提供的更高级的语言功能。
我目前正在考虑用 Tasks 重写一些使用“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) {...}
}
所以这是我的问题...我已经阅读了很多关于任务异常处理的文章和资源,其中一些讨论了诸如检查“task.IsCompleted”和/或“ task.Status”,以及使用 TaskContinuationOptions 分支成多个 ContinueWiths。
我试图让它尽可能简单,所以在 ContinueWith 方法中简单地调用“task.Wait()”来捕获异常是否可以接受(根据上面的代码)还是有更好的方法来做到这一点?
非常感谢!
更新和回答
为了澄清起见,我应该解释一下原始代码用于 WinForms 应用程序,目标是通过异步运行它们来保持 UI 在长时间的 DB 操作(或任何其他长时间的过程)期间响应不同的线程。
Silas 和 Servy 指出,自从切换到 C# 5.0,我应该使用 async/await,所以这是我选择使用的类似代码对上面的例子...
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);
}
与“MethodInvoker”或“Task”方法相比,此代码至少有两个好处:-
(1) 更清晰
(2) Ater从await返回,后面的代码在UI线程上,所以不用折腾"if (this.InvokeRequired) {...}" (see Stephen Cleary's blog for more information on this)。
原来的问题呢? ContinueWith中使用Wait来捕捉异常可以吗?
我想这是一个有争议的问题,因为 async/await 显然是要走的路,但经过进一步研究,答案是肯定的,可以这样做!
【问题讨论】:
-
如果您使用的是 C# 5.0 功能,为什么不等待任务。
await就像 C# 5.0 功能。 -
这可能是一个很好的问题...我正在努力通过 O'Reilly 的 C# 6.0 in a Nutshell 并且还没有达到异步/等待的程度,但我“痒”了,想开始使用我学到的关于Tasks的知识!就是说 - 我刚刚看过那个主题,并不太明白如何以与上述类似的方式使用 async/await。 :-/
标签: c# .net winforms user-interface task-parallel-library