向后台工作程序发送参数?

168

假设我想向后台工作者发送一个整数类型的参数,应该如何实现?

private void worker_DoWork(object sender, DoWorkEventArgs e) {

}

我知道这个是worker.RunWorkerAsync();,但我不理解如何在worker_DoWork中定义它应该使用一个int参数。

8个回答

267

你可以这样开始:

int value = 123;
bgw1.RunWorkerAsync(argument: value);  // the int will be boxed

然后

private void worker_DoWork(object sender, DoWorkEventArgs e) 
{
   int value = (int) e.Argument;   // the 'argument' parameter resurfaces here

   ...

   // and to transport a result back to the main thread
   double result = 0.1 * value;
   e.Result = result;
}


// the Completed handler should follow this pattern 
// for Error and (optionally) Cancellation handling
private void worker_Completed(object sender, RunWorkerCompletedEventArgs e) 
{
  // check error, check cancel, then use result
  if (e.Error != null)
  {
     // handle the error
  }
  else if (e.Cancelled)
  {
     // handle cancellation
  }
  else
  {          
      double result = (double) e.Result;
      // use it on the UI thread
  }
  // general cleanup code, runs when there was an error or not.
}

39
我可以翻译成中文:如何传递两个参数? - sooprise
3
还是我发送一个包含多个参数的对象? - sooprise
23
使用一个辅助类或者Tuple<A,B>(C#4+)来打包数据(编辑:是的,使用一个对象将所有数据打包起来。例如可以看一下DoWorkEventArgs self)。 - H H
但是你如何通知UI结果呢? - rayray
1
@rayray: 在我标记为安全的地方,label1.Text = e.Result.ToString(); - H H

108

虽然这个问题已经有了答案,但我想提供另一种选择,我认为这种方法更易于阅读:

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (obj, e) => WorkerDoWork(value, text);
worker.RunWorkerAsync();

在处理程序方法中:

private void WorkerDoWork(int value, string text) {
    ...
}

13
我之前不知道IMO是什么意思,我以为它是C#的一个东西。我在谷歌上搜了"C# IMO",然后就来到了这里,并且找到了答案...哈哈。https://www.quantnet.com/threads/c-c-vba-or-java.11433/ - electricalbah
三个参数怎么样? - YukiSakura
自2012年以来,我就没有再使用.NET了,但如果我没记错的话,只要与方法签名匹配,你可以添加想要的参数 ... => WorkerDoWork(a, b, c);,如 ... WorkerDoWork(int a, string b, string c) {... - dcarneiro
1
请注意,如果您使用了这个(就像我尝试过的那样),每次都必须创建一个新的BackgroundWorker(就像您的示例中所做的那样)。否则,您将遇到像我一样的问题。我的BackgroundWorker会重复之前的运行。如果只运行一次,那么它是正常的。运行两次会重复上一次和当前运行。第三次运行将重复最后两次和当前运行。等等。 - B. Shea
但是值是如何传递到RunWorkerAsync中的呢? - CodyBugstein

55
你可以这样传递多个参数。
List<object> arguments = new List<object>();
arguments.Add("first");      //argument 1
arguments.Add(new Object()); //argument 2
// ...
arguments.Add(10);           //argument n

backgroundWorker.RunWorkerAsync(arguments);

private void worker_DoWork(object sender, DoWorkEventArgs e) 
{
  List<object> genericlist = e.Argument as List<object>;
  //extract your multiple arguments from 
  //this list and cast them and use them. 
}

@missReclusive将“genericlist”项强制转换,例如,假设“argument 1”的类型为int,则int argument1 =(int)genericlist [0] - Zain Ali
2
从维护的角度来看,使用List<object>是一个不好的想法。你应该使用具体类型,因为至少你能够弄清楚自己在做什么(请参见下面我的答案中的示例)。 - Denis
我可能更喜欢使用Tuple(或专门的类),而不是一组通用对象的列表。 - James S

9
你可以使用DoWorkEventArgs.Argument属性。
在微软的网站上可以找到一个完整的示例(甚至使用int参数):

7

请查看DoWorkEventArgs.Argument Property,它与IT技术有关。

...
backgroundWorker1.RunWorkerAsync(yourInt);
...

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    // Do not access the form's BackgroundWorker reference directly.
    // Instead, use the reference provided by the sender parameter.
    BackgroundWorker bw = sender as BackgroundWorker;

    // Extract the argument.
    int arg = (int)e.Argument;

    // Start the time-consuming operation.
    e.Result = TimeConsumingOperation(bw, arg);

    // If the operation was canceled by the user, 
    // set the DoWorkEventArgs.Cancel property to true.
    if (bw.CancellationPending)
    {
        e.Cancel = true;
    }
}

7

如果您想传递多种类型的参数,可以尝试这个方法,首先将它们全部添加到一个类型为Object的数组中,然后将该对象传递给RunWorkerAsync()。以下是一个例子:

   some_Method(){
   List<string> excludeList = new List<string>(); // list of strings
   string newPath ="some path";  // normal string
   Object[] args = {newPath,excludeList };
            backgroundAnalyzer.RunWorkerAsync(args);
      }

现在在后台工作者的doWork方法中

backgroundAnalyzer_DoWork(object sender, DoWorkEventArgs e)
      {
        backgroundAnalyzer.ReportProgress(50);
        Object[] arg = e.Argument as Object[];
        string path= (string)arg[0];
        List<string> lst = (List<string>) arg[1];
        .......
        // do something......
        //.....
       }

2
+1. 以这种方式发送参数也避免了每次运行都要启动新的BackgroundWorker来避免重复(至少在我的应用程序中是这样)。请参见我下面关于此问题的评论。另请参阅https://dev59.com/Xmct5IYBdhLWcg3wPbMm#12231431和http://stackoverflow.com/questions/12507602/c-sharp-backgroundworker-keep-on-running-dowork。 - B. Shea
我的强制转换失败了 _dirs = (string[])e.Argument; 但是这个 _dirs = e.Argument as string[]; 是有效的。强制转换尝试将其转换为接口,而代码编译通过了... 非常感谢! - Marcelo Scofano Diniz

5

4

在使用对象类型列表时,应尽可能使用具体类型的组合对象(使用组合设计模式)。谁会记得每个对象到底是什么?考虑以后代码维护的问题...相反,尝试使用以下方法:

Public (Class or Structure) MyPerson
                public string FirstName { get; set; }
                public string LastName { get; set; }
                public string Address { get; set; }
                public int ZipCode { get; set; }
End Class

然后:
Dim person as new MyPerson With { .FirstName = “Joe”,
                                  .LastName = "Smith”,
                                  ...
                                 }
backgroundWorker1.RunWorkerAsync(person)

然后:
private void backgroundWorker1_DoWork (object sender, DoWorkEventArgs e)
{
        MyPerson person = e.Argument as MyPerson
        string firstname = person.FirstName;
        string lastname = person.LastName;
        int zipcode = person.ZipCode;                                 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接