繁体   English   中英

如何从同步创建异步方法

[英]How to create async method from sync

(下面的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

...此选项不起作用,我认为这是因为Task.Run在不同的线程中运行,因此在更新组合框时发生了奇怪的事情(抱歉,描述如此含糊,我真的不知道更好)。

因此,我发现了一个类似的SO问题 ,但没有令人满意的答案,这使我认为不是那么简单。 希望我错了。


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
    })
}

首先: 要非常小心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);
}

db调用应该是可以等待的,但是对于我来说,更改对我来说是非常昂贵的……所以执行fetch操作的Task.Run()是一个糟糕的主意

如您所述,理想的解决方案是使其始终处于异步状态。 因此,下面的解决方案是骇客(以避免过多的代码更改),而不是最佳实践。

也就是说,您可以在此处使用async voidTask.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.
  }
}

特别是在设置UI控件的属性时访问UI控件时使用Dispatcher ,奇怪的事情可能消失了。 从Task.Run中的任何地方获取数据,但是应该使用分派器访问在UI控件中设置属性的代码。 可能这将是您的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM