async方法必须返回Task或Task,否则编译报错;await只能在async方法内使用;禁用.Result/.Wait()防死锁;类库中推荐ConfigureAwait(false)。
不满足这个条件的 async 方法在编译时就会报错

void(除事件处理器外)或 int。这是最基础也最容易忽略的约束。
async Task 用于无返回值的异步操作,如 async Task SaveAsync()
async Task 用于有返回值的异步操作,调用后可用 await 获取 string 结果async void DoSomething() —— 无法被等待、异常会直接崩掉线程、难以测试试图在普通方法里写 await SomeAsyncMethod() 会触发编译错误 CS4032:“The 'await' operator can only be used within an async method.”
async 就行”,还要同步改返回类型(见上一条)async void,但仅限这一层async Task,而非 async void
在 ASP.NET Core 或 WinForms 中调用 task.Result 或 task.Wait() 极易引发死锁,尤其在有同步上下文(SynchronizationContext)的环境里。
async + await,让整个调用链异步穿透Task.Run(() => SomeAsyncMethod()).Result 绕过上下文,但这是权宜之计,不是设计选择在非 UI、非 ASP.NET 传统管线(如 .NET Core Web API、类库、工具函数)中,await task.ConfigureAwait(false) 能避免不必要的上下文捕获,提升性能并防止潜在死锁。
ConfigureAwait(false) 影响不大,但加了也没坏处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); }