async方法必须返回Task或Task,否则编译报错;await只能在async方法内使用;禁用.Result/.Wait()防死锁;类库中推荐ConfigureAwait(false)。

async 方法必须返回 Task 或 Task
不满足这个条件的 async 方法在编译时就会报错,比如返回 void(除事件处理器外)或 int。这是最基础也最容易忽略的约束。
-
async Task用于无返回值的异步操作,如async Task SaveAsync() -
async Task用于有返回值的异步操作,调用后可用await获取String结果 - 避免写
async void DoSomething()—— 无法被等待、异常会直接崩掉线程、难以测试
await 只能在 async 方法内部使用
试图在普通方法里写 await SomeAsyncMethod() 会触发编译错误 CS4032:“The ‘await’ operator can only be used within an async method.”
- 不是“加个
async就行”,还要同步改返回类型(见上一条) - 如果调用链顶端是 ui 事件(如按钮点击),可合法用
async void,但仅限这一层 - Web API 控制器中应始终用
async Task,而非async void
不要用 .Result 或 .Wait() 阻塞异步方法
在 ASP.net Core 或 winForms 中调用 task.Result 或 task.Wait() 极易引发死锁,尤其在有同步上下文(SynchronizationContext)的环境里。
- 典型死锁现象:UI 线程卡住 / http 请求永远不返回 / 日志停在某一行不动
- 替代方案:把调用点也改成
async+await,让整个调用链异步穿透 - 实在无法改(如老代码或第三方同步接口),可用
Task.Run(() => SomeAsyncMethod()).Result绕过上下文,但这是权宜之计,不是设计选择
ConfigureAwait(false) 在类库中值得默认添加
在非 UI、非 ASP.NET 传统管线(如 .NET Core Web API、类库、工具函数)中,await task.ConfigureAwait(false) 能避免不必要的上下文捕获,提升性能并防止潜在死锁。
- ASP.NET Core 默认无 SynchronizationContext,所以
ConfigureAwait(false)影响不大,但加了也没坏处 - 在 NuGet 类库项目中建议统一加上,避免下游使用者踩坑
- UI 层(wpf/WinForms)需要更新控件时,不能加
ConfigureAwait(false),否则会抛出跨线程访问异常
public async Task FetchDataAsync() { var response = await httpClient.GetAsync("https://api.example.com/data") .ConfigureAwait(false); // 类库中推荐 return await response.Content.ReadAsStringAsync() .ConfigureAwait(false); }
异步的本质不是“多线程”,而是“不阻塞当前线程”。很多人一上来就想着开新线程,反而绕远了。真正容易出问题的地方,往往藏在返回类型和上下文切换这两处。