先用几个例子展示这个语法糖的优势
public async Task<bool> ComplexBusinessFlow_Clean(int orderId)
{
try
{
// 1. 验证订单
var validation = await orderService.ValidateOrderAsync(orderId);
if (!validation.IsValid)
return false;
// 2. 处理支付
var paymentResult = await paymentService.ProcessPaymentAsync(orderId);
if (!paymentResult.Success)
return false;
// 3. 更新库存
await inventoryService.UpdateStockAsync(orderId);
// 4. 发送确认邮件
await emailService.SendConfirmationAsync(orderId);
Console.WriteLine("业务流程完成");
return true;
}
catch (Exception ex)
{
logger.LogError(ex, $"订单 {orderId} 处理失败");
return false;
}
}
执行顺序分析
// 1. 验证订单 - 第一步 var validation = await
orderService.ValidateOrderAsync(orderId);
// 2. 处理支付 - 第二步(必须等第一步完成) var paymentResult = await paymentService.ProcessPaymentAsync(orderId);
// 3. 更新库存 - 第三步(必须等第二步完成) await inventoryService.UpdateStockAsync(orderId);
// 4. 发送确认邮件 - 第四步(必须等第三步完成) await emailService.SendConfirmationAsync(orderId);
关键特性 //用写同步代码的风格达到了异步执行的效果
-
顺序执行 :每个
await都会等待前一个异步操作完成后再执行下一个 -
非阻塞:虽然顺序执行,但不会阻塞线程(在等待时可以处理其他任务)
-
异常处理:统一的
try-catch块确保任何步骤出错都会进入异常处理private async void btnLoadData_Click(object sender, EventArgs e)
{
try
{
progressBar.Visible = true;
btnLoad.Enabled = false;// ✅ 异步等待,不阻塞UI线程 var data = await httpClient.GetStringAsync(url); // 自动回到UI线程上下文 textBox.Text = data; } catch (Exception ex) { MessageBox.Show($"加载失败: {ex.Message}"); } finally { progressBar.Visible = false; btnLoad.Enabled = true; }}
来详细分析这段代码的执行顺序和执行所在线程:
执行顺序分析
-
用户点击按钮 → UI线程
-
执行同步代码段:
-
progressBar.Visible = true→ UI线程 -
btnLoad.Enabled = false→ UI线程
-
-
遇到await表达式:
-
启动
GetStringAsync()异步操作 → 后台线程 -
方法在此暂停 ,控制权返回给调用者
-
-
异步操作完成后:
-
自动回到UI线程上下文
-
继续执行await后面的代码
-
-
更新UI:
textBox.Text = data→ UI线程
-
异常处理/清理:
- catch或finally块 → UI线程
线程切换示意图
UI线程: [点击] → [显示进度条] → [禁用按钮] → [暂停等待] → [恢复] → [更新文本框] → [隐藏进度条] ↓ 后台线程: [HTTP请求执行]...
关键线程信息
| 代码段 | 执行线程 | 说明 |
|---|---|---|
progressBar.Visible = true |
UI线程 | 同步执行 |
btnLoad.Enabled = false |
UI线程 | 同步执行 |
await httpClient.GetStringAsync() |
后台线程池 | I/O完成端口线程 |
textBox.Text = data |
UI线程 | 自动回到原始上下文 |
finally块中的代码 |
UI线程 | 同步执行 |
重要特性
-
不会阻塞UI:await期间UI线程可以处理其他消息
-
自动线程上下文恢复:await完成后自动回到UI线程
-
异常处理安全:任何异常都会在UI线程的catch块中处理
取消操作
使用 CancellationToken
public async Task<string> DownloadWithCancelAsync(string url,
CancellationToken cancellationToken = default)
{
using var client = new HttpClient();
// 传递取消令牌
HttpResponseMessage response = await client.GetAsync(url, cancellationToken);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
// 使用示例
public static async Task Main()
{
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); // 5秒后取消
try
{
var result = await DownloadWithCancelAsync("https://example.com", cts.Token);
Console.WriteLine(result);
}
catch (OperationCanceledException)
{
Console.WriteLine("操作被取消");
}
}