为什么/如何在没有DoWorkEventArgs的情况下使用BackgroundWorker?

Rhy*_*led 0 c# backgroundworker

以下是我正在研究的类的一个简化版本(WinForms项目的一部分):

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

    public ReportBuilder(MyAPI apiAccess, List<Project> selectedProjects){
        this.apiObject = apiAccess;
        this.projects = selectedProjects;
    }

    public void DownloadData(){
        BackgroundWorker workerThread = new BackgroundWorker();
        workerThread.DoWork += (sender, e) => this.retrieveInvoices(this.projects); // yes, the parameter is unnecessary in this case, since the variable is in scope for the method anyway, but I'm doing it for illustrative purposes
        workerThread.RunWorkerCompleted += receiveData;
        workerThread.RunWorkerAsync();
    }

    private void retrieveInvoices(List<Project> filterProjects){
        Notification status;
        if (filterProjects == null){this.invoices = this.apiObject.GetInvoices(out status);}
        else {this.invoices = this.apiObject.GetInvoices(filterProjects, out status);}
    }

    private void receiveData(Object sender, RunWorkerCompletedEventArgs e){
        // display a save file dialog to the user
        // call a method in another class to create a report in csv format
        // save that csv to file

        // ... ideally, this method would to have access to the 'status' Notification object from retrieveInvoices, but it doesn't (unless I make that an instance variable)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,通常DoWork事件处理程序的方法签名将是这样的:

private void retrieveInvoices(object sender, DoWorkEventArgs e)
Run Code Online (Sandbox Code Playgroud)

但是,正如您在上面所看到的,我的retrieveInvoices方法的签名与此不匹配.因此我预计它会失败(要么不编译,要么只在UI线程上运行retrieveInvoices,阻止它,而不是在后台工作程序中).令我惊讶的是它似乎正在起作用,但由于我见过的所有BackgroundWorker示例都没有这样做,我仍然认为我一定做错了.但是我,为什么?

Pan*_*vos 6

这条线:

worker.DoWork += (sender, e) => this.retrieveInvoices(this.projects); 
Run Code Online (Sandbox Code Playgroud)

引入一个带有参数的委托,该参数使用参数(object sender, DoWorkEventArgs e)调用方法.没有语法不匹配.retrieveInvoicesprojects

这相当于:

worker.DoWork += (sender, e) => { this.retrieveInvoices(this.projects); }
Run Code Online (Sandbox Code Playgroud)

要么

void doSomething(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    this.retrieveInvoices(this.projects);
}

worker.DoWork += doSomething;
Run Code Online (Sandbox Code Playgroud)

retrieveInvoices用作实际的事件处理程序,您必须编写:

worker.DoWork += retrieveInvoices;
Run Code Online (Sandbox Code Playgroud)

这会导致不匹配.

BTW BackgroundWorker已经过时了.使用Task.Run,​​async/await和IProgress可以完成它所做的任何事情.例如,BGW不能用于组合多个异步操作.`async/await同样容易,例如:

async Task<Report> RunReport(Project[] projects, IProgress<string> progress)
{
    var data= await retrieveInvoices(projects);
    progress.Report("Invoices retrieved");
    var report=await render(data);
    progress.Report("Report rendered");
    await SaveReport(report);
    progress.Report("Report saved");
    return report;
}

//...
Progress<string> progress=new Progress<string>(msg=>statusBar1.Text=msg);

await RunReport(projects);
Run Code Online (Sandbox Code Playgroud)