我需要让RunWorkerAsync()
返回List<FileInfo>
。如何从后台工作者返回一个对象?
答案 0 :(得分:91)
在DoWork
的{{1}}事件处理程序中(后台工作发生的位置),有一个参数BackgroundWorker
。该对象具有公共属性对象Result。当您的工作人员生成结果时(在您的情况下为DoWorkEventArgs
),请将List<FileInfo>
设置为该结果,然后返回。
现在您的BackgroundWorker已完成其任务,它会触发e.Result
事件,该事件有RunWorkerCompleted
个对象作为参数。 RunWorkerCompletedEventArgs
将包含RunWorkerCompletedEventArgs.Result
。
示例:
BackgroundWorker
答案 1 :(得分:19)
我假设您不想阻止并等待RunWorkerAsync()获取结果(如果您这样做,则没有理由运行异步!
如果要在后台进程完成时收到通知,请挂钩RunWorkerCompleted事件。如果要返回某个状态,请将其返回到DoWork事件参数的Result成员中。
编辑:我过早发布了 - 完成了我的代码示例
示例:
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// do your thing
....
// return results
e.Result = theResultObject;
}
// now get your results
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MyResultObject result = (MyResultObject)e.Result;
// process your result...
}
答案 2 :(得分:1)
RunWorkerAsync()
以异步方式启动进程,并在进程实际完成之前返回并继续执行代码。如果要获取BackgroundWorker
的结果,则需要创建一个实例变量来保存该值,并在BackgroundWorker
完成后进行检查。
如果您想等到工作完成,那么您不需要BackgroundWorker
。
答案 3 :(得分:1)
您可以让您的线程以对象作为参数引发事件:
ThreadFinishedEvent(this, new ThreadEventArgs(object));
其中:
public class ThreadEventArgs : EventArgs
{
public ThreadEventArgs(object object)
{
Object = object
}
public object Object
{
get; private set;
}
}
答案 4 :(得分:1)
要补充 David 的答案,您可能希望推送一个元组以向方法提供多个参数。
为此,让我更新他的答案,其中一个值(称为engagementId)通过每个调用传递,并且元组保存原始项目以供使用以及结果。 >
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
var engagementId = (int)e.Argument;
int result = 2 + 2;
e.Result = (engagementId, result);
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
(int engagementId, int result) tupleResult = ((int, int)) e.Result; // Both (( are needed for tuple/casting.
MessageBox.Show($"Result received {tupleResult.result} for engagement {tupleResult.engagementId}");
}
有关详细信息,请参阅 How To Cast To A Tuple 的答案。
答案 5 :(得分:0)
根据您的模型,您要么让工作线程在完成工作时回调给它的创建者(或其他进程),要么必须经常轮询工作线程以查看是否已完成如果是的话,得到结果。
等待工作线程返回其结果的想法破坏了多线程的好处。
答案 6 :(得分:0)
一般来说,当运行进程异步时,工作线程应调用委托或触发事件(如ChrisF)。
你可以查看新的PFX,它具有一些可以返回值的并发功能。
例如,有一个名为Parallel.ForEach()的函数,它有一个可以返回值的重载。
查看更多信息
答案 7 :(得分:-1)
不要在“DoWork”方法中进行后台工作,而是创建一个返回您想要返回的类型的方法,并将其应用到 e.Result 中,就像这里推荐的其他答案一样。作为回答 OP 问题而又不会使问题过于复杂的最小示例...
private List<FileInfo> FileInfoWorker(object sender, DoWorkEventArgs e)
{
return new List<FileInfo>(new DirectoryInfo("C:\\SOTest").GetFiles().ToList());
}
private void bgwTest_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
e.Result = FileInfoWorker(worker, e);
}
private void bgwTest_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
tbStatus.Text = "Background operation cancelled.";
}
else
{
tbStatus.Text = "Background operation complete.";
}
}
该示例还展示了如何从 BackgroundWorker API 更新 TextBox。未显示支持通过 ProgressBar 和 TextBoxes 报告进度以及支持取消,API 中也支持这两者。代码通过按钮运行...
private void btnSOTest_Click(object sender, EventArgs e)
{
bgwTest.RunWorkerAsync();
}