如何使BackgroundWorker返回一个对象

时间:2009-06-02 13:42:58

标签: c# concurrency asynchronous backgroundworker worker-process

我需要让RunWorkerAsync()返回List<FileInfo>。如何从后台工作者返回一个对象?

8 个答案:

答案 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()的函数,它有一个可以返回值的重载。

查看更多信息

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

答案 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();
    }