委托实战案例

这个实战案例非常经典,它完美地结合了 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 委托,你的下载器类可以被复用到任何项目中。
相关推荐
MediaTea3 分钟前
<span class=“js_title_inner“>Python:实例对象</span>
开发语言·前端·javascript·python·ecmascript
热爱编程的小刘12 分钟前
Lesson04---类与对象(下篇)
开发语言·c++·算法
毕设源码-朱学姐15 分钟前
【开题答辩全过程】以 基于Java的九价疫苗预约系统为例,包含答辩的问题和答案
java·开发语言
雨季66624 分钟前
Flutter 三端应用实战:OpenHarmony “微光笔记”——在灵感消逝前,为思想点一盏灯
开发语言·javascript·flutter·ui·dart
yugi98783825 分钟前
遗传算法优化的极限学习机模型(GA-ELM)Matlab实现
开发语言·matlab
梦梦代码精38 分钟前
开源、免费、可商用:BuildingAI一站式体验报告
开发语言·前端·数据结构·人工智能·后端·开源·知识图谱
郝学胜-神的一滴1 小时前
Linux网络编程之listen函数:深入解析与应用实践
linux·服务器·开发语言·网络·c++·程序人生
焱童鞋1 小时前
解决 MeteoInfoLab 3.9.11 中 contourfm 导致的 ArrayIndexOutOfBoundsException
开发语言·python
lzhdim1 小时前
C#开发的提示显示例子 - 开源研究系列文章
开发语言·c#
人工智能AI技术1 小时前
【C#程序员入门AI】向量数据库入门:C#集成Chroma/Pinecone,实现AI知识库检索(RAG基础)
人工智能·c#