You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何/如何在不使用DoWorkEventArgs的情况下使用BackgroundWorker?

如何在不使用DoWorkEventArgs的情况下使用BackgroundWorker

其实这个需求完全可以实现,核心思路就是利用你的ReportBuilder类自身的成员变量来管理输入、输出数据,而不是依赖DoWorkEventArgs的Argument或Result属性。毕竟你的类已经持有了apiObject和selectedProjects这些关键数据,后台线程直接访问这些成员就足够了。

下面是修改并完善后的代码示例,适配你的需求:

class ReportBuilder { 
    private List<Project> projects;
    private List<Invoice> invoices;
    private MyAPI apiObject;

    // 自定义事件,方便UI层监听进度和完成状态
    public event ProgressChangedEventHandler ProgressUpdated;
    public event RunWorkerCompletedEventHandler WorkCompleted;

    public ReportBuilder(MyAPI apiAccess, List<Project> selectedProjects){
        this.apiObject = apiAccess;
        this.projects = selectedProjects;
        this.invoices = new List<Invoice>(); // 初始化结果集合
    }

    public void DownloadData(){
        BackgroundWorker workerThread = new BackgroundWorker();
        
        // 如果需要进度更新或取消功能,开启这两个开关
        workerThread.WorkerReportsProgress = true;
        workerThread.WorkerSupportsCancellation = true;

        // DoWork委托中直接使用类的成员变量,完全不需要DoWorkEventArgs的参数
        workerThread.DoWork += (sender, e) => {
            var worker = sender as BackgroundWorker;
            int processedCount = 0;

            foreach (var project in projects)
            {
                // 检查是否有取消请求
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }

                // 调用API获取当前项目的发票
                var projectInvoices = apiObject.GetInvoicesForProject(project.Id);
                invoices.AddRange(projectInvoices);

                // 计算并报告进度
                processedCount++;
                int progress = (int)((processedCount / (double)projects.Count) * 100);
                worker.ReportProgress(progress);
            }
        };

        // 将后台线程的进度事件转发给类的自定义事件,方便UI层处理
        workerThread.ProgressChanged += (sender, e) => {
            ProgressUpdated?.Invoke(this, e);
        };

        // 工作完成后的处理,同样利用类成员获取结果,不用依赖e.Result
        workerThread.RunWorkerCompleted += (sender, e) => {
            if (e.Error != null)
            {
                // 这里可以添加错误处理逻辑,比如通知UI层出错了
            }
            else if (e.Cancelled)
            {
                // 处理用户取消操作的场景
            }
            else
            {
                // 此时this.invoices已经填充完成,可以供外部调用
            }
            // 通知UI层工作完成
            WorkCompleted?.Invoke(this, e);
        };

        // 启动后台任务
        workerThread.RunWorkerAsync();
    }

    // 提供一个安全的方法让外部获取结果(建议在WorkCompleted事件触发后调用)
    public List<Invoice> GetInvoices()
    {
        // 返回副本避免外部直接修改内部集合,保证线程安全
        return new List<Invoice>(invoices);
    }
}

关键要点说明

  • 抛弃DoWorkEventArgs的核心逻辑:你的类已经封装了所有需要的输入(apiObject、projects)和输出(invoices)数据,后台线程可以直接访问这些成员,完全不需要通过e.Argument传递参数,也不用e.Result返回结果。
  • 进度与取消支持:如果需要这些功能,只需开启BackgroundWorker对应的属性,在DoWork委托中检查取消状态、报告进度即可,最后通过自定义事件把状态传递给UI层。
  • 线程安全注意:获取结果时返回集合的副本,并且建议在WorkCompleted事件触发后再调用GetInvoices,避免UI线程和后台线程同时操作集合导致的冲突。

内容的提问来源于stack exchange,提问作者Rhydgaled

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:59:05