Why/How BackgroundWorker 是否在没有 DoWorkEventArgs 的情况下工作?
Why/How Does BackgroundWorker Work Without DoWorkEventArgs?
以下是我正在处理的class(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)
}
}
现在,DoWork 事件处理程序的方法签名通常是这样的:
private void retrieveInvoices(object sender, DoWorkEventArgs e)
但是,正如您在上面看到的,我的 retrieveInvoices 方法的签名不匹配。因此我预计它会失败(要么不编译,要么只是 UI 线程上的 运行 retrieveInvoices,阻塞它,而不是在后台工作程序中)。令我惊讶的是,它似乎在工作,但自从我看到 none 的 BackgroundWorker 示例这样做以来,我仍然认为我一定做错了什么。但是我是吗,为什么?
行:
worker.DoWork += (sender, e) => this.retrieveInvoices(this.projects);
引入一个带有参数 (object sender, DoWorkEventArgs e)
的委托,该委托使用参数 projects
调用方法 retrieveInvoices
。没有语法不匹配。
这相当于:
worker.DoWork += (sender, e) => { this.retrieveInvoices(this.projects); }
或
void doSomething(object sender, System.ComponentModel.DoWorkEventArgs e)
{
this.retrieveInvoices(this.projects);
}
worker.DoWork += doSomething;
要使用 retrieveInvoices
作为实际的事件处理程序,您必须编写:
worker.DoWork += retrieveInvoices;
这会导致不匹配。
顺便说一句,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);
以下是我正在处理的class(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)
}
}
现在,DoWork 事件处理程序的方法签名通常是这样的:
private void retrieveInvoices(object sender, DoWorkEventArgs e)
但是,正如您在上面看到的,我的 retrieveInvoices 方法的签名不匹配。因此我预计它会失败(要么不编译,要么只是 UI 线程上的 运行 retrieveInvoices,阻塞它,而不是在后台工作程序中)。令我惊讶的是,它似乎在工作,但自从我看到 none 的 BackgroundWorker 示例这样做以来,我仍然认为我一定做错了什么。但是我是吗,为什么?
行:
worker.DoWork += (sender, e) => this.retrieveInvoices(this.projects);
引入一个带有参数 (object sender, DoWorkEventArgs e)
的委托,该委托使用参数 projects
调用方法 retrieveInvoices
。没有语法不匹配。
这相当于:
worker.DoWork += (sender, e) => { this.retrieveInvoices(this.projects); }
或
void doSomething(object sender, System.ComponentModel.DoWorkEventArgs e)
{
this.retrieveInvoices(this.projects);
}
worker.DoWork += doSomething;
要使用 retrieveInvoices
作为实际的事件处理程序,您必须编写:
worker.DoWork += retrieveInvoices;
这会导致不匹配。
顺便说一句,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);