【问题标题】:Where do I call an async method from?我从哪里调用异步方法?
【发布时间】:2015-08-19 16:33:36
【问题描述】:

我在调用异步方法时遇到了一些麻烦。该方法在一个类中并加载一个文本文件。我想在应用程序启动时加载文本文件。但是,我不能从构造函数调用异步方法。我在网上看到的大多数示例都经常调用异步按钮按下事件中的方法。

目前,我正在从我的构造函数中尝试这个:

Task.Run(async () =>
{
    this.categories = await GenerateCategories(numberOfCategories);
});

虽然这可行,但程序的其余部分在调用此方法后继续执行,并且执行使用“类别”的代码导致崩溃(因为类别仍然为空,因为任务尚未完成)。

总而言之,从哪里以及如何最好地调用此方法?我不希望它在用户按下按钮或任何东西时加载,我希望在执行更多代码之前填充“类别”。

我正在使用 C# 并编写一个通用应用程序,因此加载文件必须是异步的。

【问题讨论】:

  • 不确定通用应用程序,但 winforms,我相信 WPF 有表单的加载事件,这不会在这里工作吗?
  • 所以我认为你需要稍微改变一下你的流程。您应该继续异步运行此任务(即脱离 UI 线程)。但是,您需要应用程序中的其他进程跟随这个进程,而不是在此任务执行时同时发生。需要更多地了解您的应用才能提出解决方案。
  • 您可以创建一个异步工厂方法来返回您的类的实例。您的构造函数可以是同步的,然后加载此数据。或者在类中添加一个异步方法来加载数据发布构造函数,并使用工厂方法在一个步骤中为您完成这一切。
  • 如果您在 UI 线程上运行的其他方法取决于 categories 字段的存在,那么您需要在 UI 上同步运行该 GenerateCategories线程也。但是您应该改为在 GenerateCategories 之后异步运行其他方法。

标签: c# file-io windows-runtime async-await win-universal-app


【解决方案1】:

我的博客上有一个关于using async in "impossible" situations 的系列;一篇文章特别涵盖了async constructors

由于您正在编写通用应用程序,因此需要牢记的重要一点是用户界面最初必须立即(同步)显示;在初始视图显示之前进行异步工作根本不是一种选择。相反,您应该(同步)初始化/构造到“加载”状态,然后在加载文件时更新您的 UI。

我有一个three-part series of MSDN articles on asynchronous patterns for MVVM applications,您可能会觉得有帮助。

【讨论】:

    【解决方案2】:

    简单的答案是 Task.Run() 返回一个任务。如果您在任务上调用 .Wait() 方法,您的线程将暂停,直到任务完成并设置类别成员。

    但是,这忽略了该方法可能是出于某种原因异步创建的。您可能不想占用 UI 线程 Wait() 来完成异步方法。您可能还需要注意 Task.Run 手册页上的此注释:

    语言编译器使用 Run(Func) 方法来支持 async 和 await 关键字。不打算直接调用 来自用户代码。

    相反,您可以创建一个 async void 方法来从构造函数调用,该构造函数将在后台线程中异步运行任务。您应该确保所有依赖于 GenerateCategories 运行的逻辑都是从该方法运行的。

    要正确使用异步方法,您必须将它们的控制流与主用户界面线程分离。当任务需要通知 UI 其进度时,您可以使用 Control.Invoke 从任务内部向 UI 发送消息。

    【讨论】:

      猜你喜欢
      • 2020-12-19
      • 1970-01-01
      • 1970-01-01
      • 2017-09-23
      • 2017-03-06
      • 1970-01-01
      • 2011-03-04
      • 1970-01-01
      相关资源
      最近更新 更多