委托实战案例

这个实战案例非常经典,它完美地结合了 Action<T>(进度回调委托)Task(异步操作载体)CancellationTokenSource(超时与取消机制)

我们将构建一个模拟下载器,它可以一边下载一边通过委托汇报进度,同时如果超过规定时间则自动停止。


1. 核心设计思路

  • 进度汇报: 使用 Action<int> 委托,由下载逻辑在循环中调用。
  • 超时处理: 使用 CancellationTokenSource 配合 CancelAfter 方法,这是现代 C# 处理超时的标准做法。
  • 异步封装: 使用 Task.Run 将下载逻辑放入后台,避免阻塞 UI。

2. 实战代码实现

csharp 复制代码
using System;
using System.Threading;
using System.Threading.Tasks;

public class FileDownloader
{
    // 异步下载方法
    // progressCallback: 一个接收 int (0-100) 的委托,用于更新进度
    // ct: 用于监听超时或取消操作的令牌
    public async Task DownloadFileAsync(string url, Action<int> progressCallback, CancellationToken ct)
    {
        Console.WriteLine($"开始从 {url} 下载...");

        for (int i = 1; i <= 10; i++)
        {
            // 检查是否已经超时或被取消
            ct.ThrowIfCancellationRequested();

            // 模拟耗时的网络操作
            await Task.Delay(500, ct); 

            // 计算进度
            int progress = i * 10;

            // --- 委托的核心应用 ---
            // 调用外部传入的逻辑,调用者决定怎么显示进度(打印、进度条等)
            progressCallback?.Invoke(progress);
        }

        Console.WriteLine("\n下载完成!");
    }
}

class Program
{
    static async Task Main()
    {
        FileDownloader downloader = new FileDownloader();

        // 1. 设置超时时间为 3 秒 (若下载需要 5 秒则会触发超时)
        using var cts = new CancellationTokenSource();
        cts.CancelAfter(TimeSpan.FromSeconds(3)); 

        try
        {
            // 2. 定义进度回调委托 (使用 Lambda 表达式实现 Action<int>)
            Action<int> onProgress = (p) => {
                Console.Write($"\r当前进度: {p}% ");
            };

            // 3. 启动异步任务
            await downloader.DownloadFileAsync("https://example.com/bigfile.zip", onProgress, cts.Token);
        }
        catch (OperationCanceledException)
        {
            // 如果超时,会抛出此异常
            Console.WriteLine("\n[错误]: 下载超时或已被用户取消。");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"\n发生未知错误: {ex.Message}");
        }
    }
}

3. 深度解析:委托与任务的协作

1. 委托作为"解耦器"

在上面的代码中,FileDownloader 类并不知道如何"显示"进度。它只是持有一个 Action<int> 委托。

  • 如果是控制台程序 ,委托里写的是 Console.WriteLine
  • 如果是桌面 UI 程序 ,委托里写的可能是更新 ProgressBar 控件。
    这就实现了业务逻辑(下载)与展示逻辑(进度条)的完美分离

2. CancellationToken 的本质

CancellationToken 内部其实也依赖于委托。当你调用 CancelAfter 时,它会触发一个内部委托,通知所有持有该 Token 的代码进行"紧急避险"。

3. 执行流对比

环节 角色 作用
启动阶段 Task 开启异步执行上下文,不阻塞主线程。
运行阶段 Action<int> 作为双向通信的桥梁,从后台向前端发送实时状态。
终止阶段 CancellationToken 充当安全阀,由委托机制触发中断逻辑。

4. 为什么这样写?

  1. 非阻塞: 使用 await 确保了即使在下载,你的 UI 界面也不会卡死。
  2. 资源可控: 很多人写下载不考虑超时,导致后台线程死锁,使用 CancellationToken 是处理异步长任务的最佳实践。
  3. 高度抽象: 通过 Action 委托,你的下载器类可以被复用到任何项目中。
相关推荐
又见野草2 小时前
C++入门基础(初阶)
开发语言·c++
szm02252 小时前
Java并发
java·开发语言
一念春风2 小时前
可视化视频编辑(WPF C#)
开发语言·c#·wpf
1***43802 小时前
MATLAB高效算法实战技术文章大纲工程领域的应用背景
开发语言·算法·matlab
天“码”行空2 小时前
java的设计模式-----------单例类
java·开发语言·设计模式
0***m8222 小时前
Java性能优化实战技术文章大纲性能优化的基本原则
java·开发语言·性能优化
艾莉丝努力练剑2 小时前
【QT】环境搭建收尾:认识Qt Creator
运维·开发语言·c++·人工智能·qt·qt creator·qt5
南棱笑笑生2 小时前
20260113给飞凌OK3588-C开发板适配Rockchip原厂的Android14系统时适配CAM3接口的OV5645
c语言·开发语言·rockchip
Larry_Yanan2 小时前
Qt安卓开发(二)摄像头打开
android·开发语言·数据库·c++·qt·ui