c# 将通用 windows 应用程序转换为异步

c# converting universal windows app to async

我是 windows 的新手,我正在使用通用应用程序制作一个业余爱好项目。几天后,我发现连接串行端口的唯一方法是使用来自 SerialDevice class.

并与之相关的异步方法

我喜欢关于该主题的一般性建议:一旦你开始使用一个序列号 api,那么从 'Main' 开始将整个应用程序转换为异步会容易得多(http://blog.stephencleary.com/2012/02/async-and-await.html ) 而不是处理与异步方法的同步调用相关的问题。

然而,由 VS2015 创建的通用应用程序包含大量生成的非异步代码,这些代码并不旨在被理解。我想在某个地方有一个通用模式可以处理这个问题,但我找不到它的任何踪迹。那我该怎么办呢?

通用应用程序未被“此应用程序是异步的”和“此应用程序不是异步的”分隔,创建async 方法 而不是 意味着您必须绝对更改所有内容才能使用它们。

asyncawait 的好处之一是允许您在不冻结 UI.

的情况下执行长 运行 操作

Stephen Cleary 的“异步所有事物”模式完全没有必要,它滥用了异步方法的目的。

大多数代码不需要用异步方法包装,同步方法几乎可以处理所有事情。然而,对于 long-运行 进程,例如从 Web 服务请求数据,最适合异步方法,因为它需要很长时间。

重要的是您不要沉浸在创建数百万个 async 方法的异常模式中,找出 需要 什么是异步的并实现此功能因此。

之所以有些UWP API是async是因为有些进程不是瞬时的,调用asyncAPI方法时要记住,您要求 操作系统 代表您执行操作。事实上,操作系统可能 就绪 ,或者可能超载,可能无法立即满足您的请求,因此这些方法是异步的,这确保您的应用程序不会等待一个请求。

我建议您阅读此 here

I suppose there is a general pattern somewhere do deal with this issue but I could not find any trace of it. So what should I do?

我的建议总是这样:

  1. 从 "leaves" 开始并识别自然异步操作。对于您的情况,这很容易,因为在 Windows 通用平台中,自然异步操作 只有 具有异步 API。
  2. 使用 await 调用异步 API。
  3. await 的存在将要求调用方法为 async(您应该将其 return 类型从 void 更改为 Task 或从 TTask<T>).
  4. 此转换使调用方法异步,因此返回步骤 (2) 它是 个调用方。
  5. 重复直到找到 "root" 方法 - 在 Windows 通用应用程序中,这通常是一个事件处理程序,必须是 async void(它们不允许是async Task).

您可能 运行 通过您的代码库遇到 async "grows" 等各种问题 - 例如,您不能在 属性 中使用 await吸气剂或构造函数。我有一个 series of posts on my blog describing techniques to work around these problems.

这是新手混淆的结果。

一个。术语 'async function' 具有三个含义:

A.1。签名中有 'async' 项的函数。该术语的唯一意义是编译器不会将函数体中的 'await' 视为变量,而是将其视为 await 语句。它不会以任何其他方式更改签名,它严格用于向后兼容。

A.2。可以等待的任务类型的函数。

A.3。主体中也有 await 语句的 Task 类型的函数。

乙。 UI 处理未被 await 语句阻塞:如果来自 UI 基础设施的一个回调正在等待 await 语句,UI 消息处理仍在执行。

因此,为了从 UI 方法调用异步函数 (A.2):

(a) 将 'async' 项添加到 UI 函数签名 (A.1)。

(b) 在函数内部使用await语句调用异步库函数(A.2)

(c) 以一种或另一种方式处理异步执行的结果。

async-await 模式引起的最大困惑是该模式只不过是将一个函数包装在任务中,运行 它和 return 运行ning Task(理解这一点非常重要,因为您并不总是希望您的 Task 自动启动...)。

一旦您意识到这一点,就应该更容易理解任何异步调用都可以很容易地被这样的任务包装。

    public void PersistChanges()
    {
        var saveTask = new Task(() => PersistChangesAsync());
        saveTask.Start();
    }

当然,正如其他地方提到的,您需要确保 运行 异步调用尽可能多的异步,例如,如果您的应用程序中有一个保存按钮,您可以异步获取该事件,然后调用异步 PersistChangesAsync。

但是在我的应用程序启动时,我可能不希望在加载基本设置、验证用户或其他任何事情之前发生任何事情,然后你甚至可以使用 saveTask.RunSynchronously() (尽管很明显你仍然可以 运行 几个异步的子任务然后等待结果(如果有的话,或者在一切完成时定义一个延续任务)