使用 await 运算符解决异步方法中的错误和警告

本文介绍以下编译器错误:

  • CS1983由于这是异步方法,因此返回表达式的类型必须为“”Task<T>而不是“”。T
  • CS1985无法在 catch 子句中使用 await。
  • CS1986await”要求类型具有合适的“GetAwaiter”方法。
  • CS1989不能将异步 lambda 表达式转换为表达式树。
  • CS1991“Type”无法实现“event”,因为它是 Windows 运行时事件,“event”是常规的 .NET 事件。
  • CS1992仅当包含在用“async”修饰符标记的方法或 lambda 表达式内时,才能使用“'await”运算符。
  • CS1994async修饰符只能在具有主体的方法中使用。
  • CS1995await” 运算符只能在初始 “from” 子句的第一个集合表达式或在 “join” 子句的集合表达式中使用。
  • CS1996不能在 lock 语句体中使用 await。
  • CS1997由于函数是返回值的异步方法,因此返回关键字不得后跟对象表达式。
  • CS1998此异步方法缺少“”await运算符,并且将同步运行。请考虑使用“”await运算符等待非阻塞 API 调用,或“”await Task.Run(...)在后台线程上执行 CPU 绑定工作。
  • CS4008无法等待“void”。
  • CS4009返回入口点的 void 或 int 不能是异步的。
  • CS4014由于此调用未等待,因此在调用完成之前,当前方法的执行将继续执行。请考虑将 await 运算符应用于调用的结果。
  • CS4032await运算符只能在异步方法中使用。请考虑使用“async”修饰符标记此方法,并将其返回类型更改为“”。Task<T>
  • CS4033await运算符只能在异步方法中使用。请考虑使用“async”修饰符标记此方法,并将其返回类型更改为“”。Task
  • CS8892方法不会用作入口点,因为找到了同步入口点。
  • CS9123&“运算符不应用于异步方法中的参数或局部变量。
  • CS9330MethodImplAttribute.Async“不能手动应用于方法。标记方法“async”。

Await 表达式的要求条件

  • CS1985无法在 catch 子句中等待。
  • CS1986“'await'要求该类型具备合适的'GetAwaiter'方法。”
  • CS1992仅当包含在标记为“async”的修饰符的方法或 lambda 表达式内时,才能使用“await”运算符。
  • CS1995await”运算符只能在初始“from”子句的第一个集合表达式或“join”子句的集合表达式中使用。
  • CS1996无法在 lock 语句内部使用 await。
  • CS4008无法等待“void”。
  • CS4032await运算符只能在异步方法中使用。请考虑使用“async”修饰符标记此方法,并将其返回类型更改为“”。Task<T>
  • CS4033await运算符只能在异步方法中使用。请考虑使用“async”修饰符标记此方法,并将其返回类型更改为“”。Task

若要正确使用 await 运算符,请遵循这些规则。 有关详细信息,请参阅 使用 async 和 await 进行异步编程

  • 请勿在 catch 子句中使用 awaitCS1985)。 虽然可以在 try 块和最终块(在 C# 6 及更高版本中)中使用 await ,但 catch 块在异常处理和控制流中提出了特殊挑战。
  • 请勿在lock语句块内部使用awaitCS1996)。 编译器不支持这样做,以避免发出容易出现死锁的代码。
  • 仅在awaitCS1995)内的特定位置使用:在初始from子句的第一个集合表达式中,或在子句的join集合表达式内使用。
  • 在使用async前用await修饰符标记方法或 lambda 表达式(CS1992CS4032CS4033)。
  • 确保等待中的类型具有一个可访问的GetAwaiter方法,该方法返回一个等待器类型(CS1986)。
  • 不适用于 await 类型 voidCS4008)的表达式。
  • 将不返回值的方法的返回类型更改为 Task,将返回值的方法的返回类型更改为 Task<T>

异步方法签名要求

  • CS1983由于这是异步方法,因此返回表达式的类型必须为“”Task<T>而不是“”。T
  • CS1994async修饰符只能在具有主体的方法中使用。
  • CS4009返回入口点的 void 或 int 不能是异步的。
  • CS8892方法不会用作入口点,因为找到了同步入口点。
  • CS9330'MethodImplAttribute.Async' 不能手动应用于方法。标记方法“async”。

若要正确声明异步方法,请遵循这些签名要求。 有关详细信息,请参阅“Async main 返回值”一节。

  • 返回有效类型之一:void、、TaskTask<T>类似任务的类型IAsyncEnumerable<T>IAsyncEnumerator<T>CS1983)。
  • async仅用于带有实现的方法修饰符(CS1994)。 删除接口或类中抽象方法的async修饰符。
  • 更新到 C# 7.1 或更高版本以在入口点上使用asyncMain,或避免在早期版本中的入口点上使用asyncCS4009)。
  • 如果同时具有同步入口点和异步入口点(CS8892),请删除同步入口点。
  • 使用async关键字而不是手动应用MethodImplAttribute.AsyncCS9330)。

异步实践方法

  • CS1989不能将异步 lambda 表达式转换为表达式树。
  • CS1991“Type”无法实现“event”,因为它是 Windows 运行时事件,“event”是常规的 .NET 事件。
  • CS1997由于函数是返回值的异步方法,因此返回关键字不得后跟对象表达式。
  • CS1998此异步方法缺少“”await运算符,并且将同步运行。请考虑使用“”await运算符等待非阻塞 API 调用,或“”await Task.Run(...)在后台线程上执行 CPU 绑定工作。
  • CS4014由于此调用未等待,因此在调用完成之前,当前方法的执行将继续执行。请考虑将 await 运算符应用于调用的结果。
  • CS9123&“运算符不应用于异步方法中的参数或局部变量。

若要正确编写异步代码并避免常见的陷阱,请遵循以下最佳做法。 有关详细信息,请参阅 使用 async 和 await 进行异步编程

  • 始终对返回 TaskTask<TResult>CS4014)的异步方法调用使用 异步等待。 未等待的调用可能导致异常丢失和意外行为。
  • 不要从返回 Task (非泛型)的异步方法返回值;请改用 Task<T>CS1997)。
  • 在异步方法中至少包括一个 await 运算符,或删除 async 修饰符(CS1998)。
  • 如果方法应返回returnTask),请删除该语句。
  • 将方法的返回类型更改为 Task<T> 返回值(CS1997CS1998)。
  • 如果不需要异步状态机(async),请删除修饰符并直接返回任务。
  • 不要在表达式树中使用异步方法(CS1989)。 表达式树将代码表示为数据,不支持异步方法所需的复杂状态机转换。
  • 不要将接口或 WinRT 事件中的添加或删除访问器标记为异步(CS1991)。 这是特定于平台的限制,适用于 Windows 运行时互作性。
  • 避免对异步方法(&)中的表达式使用地址运算符()。 目标可能会在挂起期间重新定位到内存中,使指针无效。