跳到主要内容

C# 异步进度报告

介绍

在异步编程中,长时间运行的任务(如下载文件、处理数据或执行复杂计算)可能需要花费大量时间。为了提升用户体验,向用户提供任务的实时进度反馈是非常重要的。C# 提供了 IProgress<T> 接口和 Progress<T> 类,使得在异步任务中报告进度变得非常简单。

本文将详细介绍如何在 C# 中使用异步进度报告,并通过实际案例展示其应用场景。

异步进度报告的基本概念

在 C# 中,IProgress<T> 接口用于定义进度报告的回调方法。Progress<T> 类是 IProgress<T> 的一个实现,它允许你通过事件或回调函数来报告进度。

使用 IProgress<T>Progress<T>

以下是一个简单的示例,展示了如何在异步方法中使用 IProgress<T> 来报告进度:

csharp
using System;
using System.Threading.Tasks;

class Program
{
static async Task Main(string[] args)
{
var progress = new Progress<int>(percent =>
{
Console.WriteLine($"当前进度: {percent}%");
});

await LongRunningTask(progress);
}

static async Task LongRunningTask(IProgress<int> progress)
{
for (int i = 0; i <= 100; i += 10)
{
await Task.Delay(500); // 模拟耗时操作
progress?.Report(i); // 报告进度
}
}
}

输出:

当前进度: 0%
当前进度: 10%
当前进度: 20%
...
当前进度: 100%

在这个示例中,LongRunningTask 方法模拟了一个长时间运行的任务,并通过 IProgress<int> 接口报告进度。Progress<int> 类将进度值传递给回调函数,并在控制台中显示当前进度。

逐步讲解

1. 定义进度报告回调

首先,你需要定义一个回调函数来处理进度报告。这个回调函数通常是一个 Action<T>,其中 T 是进度值的类型(通常是 int 表示百分比)。

csharp
var progress = new Progress<int>(percent =>
{
Console.WriteLine($"当前进度: {percent}%");
});

2. 在异步方法中报告进度

在异步方法中,你可以通过 IProgress<T>.Report 方法来报告进度。这个方法会将进度值传递给回调函数。

csharp
static async Task LongRunningTask(IProgress<int> progress)
{
for (int i = 0; i <= 100; i += 10)
{
await Task.Delay(500); // 模拟耗时操作
progress?.Report(i); // 报告进度
}
}

3. 调用异步方法并传递进度报告对象

最后,调用异步方法时,传递 Progress<T> 对象以启用进度报告。

csharp
await LongRunningTask(progress);

实际案例

假设你正在开发一个文件下载器,你希望在下载过程中向用户显示下载进度。以下是一个简单的实现:

csharp
using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
static async Task Main(string[] args)
{
var progress = new Progress<int>(percent =>
{
Console.WriteLine($"下载进度: {percent}%");
});

await DownloadFileAsync("https://example.com/largefile.zip", progress);
}

static async Task DownloadFileAsync(string url, IProgress<int> progress)
{
using var httpClient = new HttpClient();
var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
var totalBytes = response.Content.Headers.ContentLength ?? 0;
var buffer = new byte[8192];
var bytesRead = 0L;

using var stream = await response.Content.ReadAsStreamAsync();
while (true)
{
var read = await stream.ReadAsync(buffer, 0, buffer.Length);
if (read == 0) break;

bytesRead += read;
var percent = (int)((double)bytesRead / totalBytes * 100);
progress?.Report(percent);
}
}
}

输出:

下载进度: 10%
下载进度: 20%
...
下载进度: 100%

在这个案例中,DownloadFileAsync 方法下载文件并实时报告下载进度。

总结

通过使用 IProgress<T>Progress<T>,你可以在 C# 异步编程中轻松实现进度报告。这对于提升用户体验、特别是在长时间运行的任务中,是非常有用的。

附加资源与练习

  • 练习 1: 修改 DownloadFileAsync 方法,使其在下载完成后显示“下载完成”的消息。
  • 练习 2: 尝试在进度报告中添加更多信息,例如已下载的字节数和剩余字节数。
提示

你可以通过 IProgress<T> 接口报告任何类型的进度信息,而不仅仅是百分比。例如,你可以报告当前处理的文件数量、剩余时间等。

警告

在使用 IProgress<T> 时,确保进度报告不会过于频繁,以免影响性能。