60

我需要RunWorkerAsync()返回一个List<FileInfo>.

能够从后台工作人员返回对象的过程是什么?

4

8 回答 8

100

在您的DoWork事件处理程序中BackgroundWorker(这是后台工作发生的地方)有一个参数DoWorkEventArgs. 此对象具有公共属性对象 Result。当您的工作人员生成其结果(在您的情况下为 a List<FileInfo>)时,设置e.Result为该结果并返回。

现在您的 BackgroundWorker 已经完成了它的任务,它会触发RunWorkerCompleted事件,该事件有一个RunWorkerCompletedEventArgs对象作为参数。RunWorkerCompletedEventArgs.Result将包含您的结果BackgroundWorker

例子:

private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
    int result = 2+2;
    e.Result = result;
}

private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    int result = (int)e.Result;
    MessageBox.Show("Result received: " + result.ToString());
}
于 2009-06-02T13:56:58.930 回答
25

我假设你不想阻塞并等待 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...
    }


于 2009-06-02T13:56:09.183 回答
1

RunWorkerAsync()异步启动进程,并在进程实际完成之前返回并继续执行您的代码。如果您想获得 的结果BackgroundWorker,您需要创建一个实例变量来保存该值并在BackgroundWorker完成后检查它。

如果您想等到工作完成,那么您不需要BackgroundWorker.

于 2009-06-02T13:47:36.233 回答
1

为了补充大卫的答案,人们可​​能希望通过一个元组为方法提供多个参数。

为此,让我更新他的答案,其中一个值(称为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}");
}

有关更多信息,请参阅如何转换为元组的答案。

于 2021-01-18T15:30:04.280 回答
0

根据您的模型,您要么希望工作线程在完成工作时回调其创建者(或其他进程),要么您必须经常轮询工作线程以查看它是否已完成,如果所以,得到结果。

等待工作线程返回其结果的想法破坏了多线程的好处。

于 2009-06-02T13:46:56.750 回答
0

你可以让你的线程以对象作为参数引发一个事件:

ThreadFinishedEvent(this, new ThreadEventArgs(object));

在哪里:

public class ThreadEventArgs : EventArgs
{
    public ThreadEventArgs(object object)
    {
        Object = object
    }

    public object Object
    {
        get; private set;
    }
}
于 2009-06-02T13:50:41.143 回答
0

一般来说,当运行异步进程时,工作线程应该调用委托或触发事件(如 ChrisF)。

您可以查看新的 PFX,它具有一些可以返回值的并发函数。

例如,有一个名为 Parallel.ForEach() 的函数,它有一个可以返回值的重载。

看看这个了解更多信息

http://msdn.microsoft.com/en-us/magazine/cc817396.aspx

于 2009-06-02T14:01:52.570 回答
-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();
    }
于 2021-04-21T03:34:33.587 回答