【问题标题】:How to return the e.Result value to a VB6 caller when using BackgroundWorker? [duplicate]使用 BackgroundWorker 时如何将 e.Result 值返回给 VB6 调用者? [复制]
【发布时间】:2021-03-04 14:16:34
【问题描述】:

我有以下从 VB6 应用程序调用的 工作 代码的 sn-ps。 唯一暴露的函数是 void Run() 函数。 该函数使用 backgroundWorker,我可以在 backgroundWorker_RunWorkerCompleted 中使用 e.Result 轻松查看该过程的结果。 因此,如果我从 VB6 调用 Run() ,那么一切都会完美,但我无法将 e.Result 的值返回给 VB6 调用者。 我也不能使用 string Run() 因为我在 Run() 中没有任何东西可以返回。

public void Run(string param)
{
    backgroundWorker.RunWorkerAsync(argument: param);
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    e.Result = "Done!";
}

private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    string result = (string)e.Result;
}

如何将最终字符串 (e.result) 返回给调用 void Run()?我不能只使用 e.result,因为我正在从 VB6 应用程序调用“Run()”,并且我希望在那里得到返回的结果。

感谢您的帮助...

【问题讨论】:

  • 呃,你不能。如果您想异步执行此操作,则调用代码需要支持它。制作两个函数BeginRunEndRun
  • 是否有可能让后台工作人员public?然后,您的调用代码可以订阅工作人员的RunWorkerCompleted 事件。
  • 查看现代惯用方法的最后两个副本。 IE。使用在TaskCompletionSource<T> 对象中设置值的处理程序订阅RunWorkerCompleted 事件,然后返回该对象的Task 属性作为您操作的未来结果。
  • 典型的例子是 WebBrowser,你在某处 Navigate() 并且浏览器在后台工作以加载页面。当它在几毫秒后完成时,它会引发其 DocumentCompleted 事件。做同样的事情,从 BackgroundWorker.RunWorkerCompleted 事件处理程序中引发一个事件。

标签: c# backgroundworker


【解决方案1】:

必须是后台工作人员吗?您可以在没有后台工作人员的情况下有效地实现您想要的结果:

        static void Main(string[] args)
        {
            Run();
            System.Console.ReadKey();
        }
        private static void Run()
        {
            System.Threading.Tasks.Task<string> task = DoWork();

            while (!task.IsCompleted)
            {
                System.Windows.Forms.Application.DoEvents();
            }
            System.Console.WriteLine($"Task Complete, Result=\"{task.Result}\"");
        }
        public static System.Threading.Tasks.Task<string> DoWork()
        {
            return System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                System.Threading.Thread.Sleep(1000);
                return "this is my result";
            });
        }

用后台工作者更新:

        static void Main(string[] args)
        {
            Run();
            System.Console.ReadKey();
        }
        private static System.ComponentModel.BackgroundWorker bgw;
        private static string resultWeWant = string.Empty;
        private static void Run()
        {
            bgw = new System.ComponentModel.BackgroundWorker();
            bgw.DoWork += (sender, e) =>
            {
                System.Threading.Thread.Sleep(5000);
                e.Result = "this is the result";
            };
            bgw.RunWorkerCompleted += (sender, e) =>
            {
                if (e.Error != null)
                {
                    System.Console.WriteLine($"{e.Error.ToString()}");
                }
                else
                {
                    resultWeWant = e.Result.ToString();
                }
            };
            System.Threading.Tasks.Task task = System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                bgw.RunWorkerAsync();
                while (bgw.IsBusy)
                {
                    System.Windows.Forms.Application.DoEvents();
                }
            });
            task.Wait();
            System.Console.WriteLine($"backgrounderworker is done, result=\"{resultWeWant}\"");
        }

【讨论】:

  • 如果您只是要同步等待它立即完成,它会破坏使用另一个线程的全部目的。您还不如直接从 Run 方法运行实际工作,它的行为是相同的,减去一些不必要的复杂性和性能开销。
  • 是的,完全正确。取决于我们在这里尝试实现的目标,这个问题只是要求在Run() 方法中获取字符串结果。没有提供其他规格。如果 Run() 方法可能在 UI 线程上,我们需要保持 UI 处于活动状态,那绝对是一个正当的理由,这不是一个好的答案哈哈
  • 问题试图达到什么目的无关。没有任何可能的情况下,此解决方案会比仅在当前线程中执行工作更好,这也可能不是他们想要做的,但这只是一个更糟糕的版本。跨度>
  • 是的,你是对的。对于后台工作程序,我通常看到它们用于运行流程密集型任务并使用其进度更新 UI。因此,我将假设我们希望在 UI 线程上保留 Run() 方法但保持我们的应用程序处于活动状态,从而更新我的答案。
  • 本题的目的是使用 VB6 应用程序调用 .NET DLL,该 DLL 执行异步函数并取回结果。我发现它只适用于 BackgroundWorker,但我无法返回结果。
猜你喜欢
  • 2011-07-26
  • 1970-01-01
  • 1970-01-01
  • 2010-09-28
  • 2010-11-16
  • 1970-01-01
  • 2013-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多