委托实战案例

这个实战案例非常经典,它完美地结合了 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 小时前
Unity C# 脚本学习笔记:命名空间与 using
学习·unity·c#
2601_962071572 小时前
【Java报错已解决】org.springframework.beans.factory.BeanCreationException
java·开发语言
淡海水4 小时前
07-04-并发-ConcurrentBag-T-工作窃取WorkStealing算法
开发语言·算法·c#·bag·concurrent·workstealing
点心的游戏开发世界4 小时前
Unity C# 脚本学习笔记:泛型
学习·unity·c#
CS_Zero4 小时前
C语言sizeof是函数吗?
c语言·开发语言
-今昭-5 小时前
《V2V 迁移实战:将 VMware 虚拟机转为 OpenStack 可用 Glance qcow2 镜像》
开发语言·python
黑马程序员毕设7 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
_Twink1e8 小时前
openJiuwen 实训营 Day 1 · WorkSwarm 入门教程
开发语言·c++·openjiuwen
公子小六8 小时前
基于.NET的Windows窗体编程之WinForms滑块与上下控件
windows·microsoft·c#·.net·winforms
问天_观心8 小时前
大模型微调学习(一)
开发语言·人工智能·学习·语言模型·github