如何从同步创建异步方法
本文关键字:创建 异步方法 同步 | 更新日期: 2023-09-27 18:08:13
(c#代码如下)
我刚开始学习Async和Await。我查阅了一些文章和教程,我以为我掌握了它背后的概念,但在实现一些实际示例时,我似乎碰壁了。
这是我的UI类的New():Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
PopulateUI()
End Sub
…这里的关键是PopulateUI()
。我想在不阻塞UI的情况下使用这个函数
编译器可以接受的唯一选项是:
Private Async Sub PopulateUI()
Await Task.Run(Sub()
' Do some stuff that populates the UI comboboxes
End Sub)
End Sub
…这个选项不起作用,我认为这是因为任务。Run运行在不同的线程中,所以更新组合框时会发生奇怪的事情(抱歉对描述如此模糊,我真的不知道更好)。
所以我发现了一个类似的问题,没有任何令人满意的答案,这让我觉得不是那么简单。希望我错了。
c#版本:
public MyUI()
{
// This call is required by the designer.
InitializeComponent();
// Add any initialization after the InitializeComponent() call.
PopulateUI();
}
Private async void PopulateUI()
{
await Task.Run(() =>
{
// Do some stuff that populates the UI comboboxes
})
}
db调用应该是可等待的,但是在这个时间点上,更改对我来说是相当昂贵的…那么,对
操作执行Task.Run()是不是一个糟糕的主意呢?
如您所述,理想的解决方案是使其始终是异步的。因此,下面的解决方案是一个hack(为了避免太多的代码更改),而不是最佳实践。
也就是说,你可以在这里使用async void
和Task.Run
;你只需要小心你的异常处理:
private async void PopulateUI()
{
... // Load initial view - "Loading..." message or whatever.
try
{
var data = await Task.Run(() =>
{
... // Read data from database.
});
... // Update UI with data.
}
catch (Exception ex) // Not a typo. Catch all exceptions.
{
... // Handle error - display message to user or whatever.
}
}
首先:要非常小心async void ...
:您将不会看到这样一个调用的任何异常。
我不知道这是否是规范模式(如果有这样的事情),但我通常做的是创建一个方法void CheckResult(Task task)
,它使用ContinueWith
来附加必要的错误处理(通常检查任务是否有故障并记录/显示错误对话框)。
然后我要这样做:
public MyUI()
{
// This call is required by the designer.
InitializeComponent();
// Add any initialization after the InitializeComponent() call.
CheckResult(PopulateUI());
}
private async Task PopulateUI()
{
var data = await FetchUiData();
SetControlValues(data); // or whatever
}
private static void CheckResult(Task t) {
// We want to be doing this on the UI thread
var sched = TaskScheduler.FromCurrentSynchronizationContext();
t.ContinueWith(() => {
// check if "t" faulted and perform appropriate action
}, sched);
}
在访问UI控件时使用Dispatcher,特别是在设置UI控件的属性时,奇怪的事情可能会消失。从Task中的任何位置获取数据。运行,但在UI控件中设置属性的代码应该使用dispatcher访问。