接受多个参数的BackgroundWorker替代方案?

32

BackgroundWorker对象允许我们将单个参数传递给DoWorkEventHandler。

// setup/init:
BackgroundWorker endCallWorker = new BackgroundWorker();
endCallWorker.DoWork += new DoWorkEventHandler(EndCallWorker_DoWork);
...
endCallWorker.RunWorkerAsync(userName);

// the handler:
private void EndCallWorker_DoWork(object sender, DoWorkEventArgs e)
{
    string userName = e.Argument as string;
    ...
}

为了传递多个参数,我必须将它们包装在一个对象中,就像这个可怜的字符串数组:

// setup/init:

BackgroundWorker startCallWorker = new BackgroundWorker();
startCallWorker.DoWork += new DoWorkEventHandler(StartCallWorker_DoWork);
...
startCallWorker.RunWorkerAsync(new string[]{userName, targetNumber});


// the handler:
private void StartCallWorker_DoWork(object sender, DoWorkEventArgs e)
{
    string[] args = e.Argument as string[];
    string userName = args[0];
    string targetNumber = args[1];
}

有没有其他的对象或模式可以让我们很好地传递多个参数,或者理想情况下,编写自己的签名?

7个回答

45

您可以使用闭包(Lambda):

backgroundWorker.DoWork += (s, e) => MyWorkMethod(userName, targetNumber);

或使用委托(匿名方法)语法:

backgroundWorker.DoWork += 
    delegate(object sender, DoWorkEventArgs e)
    {
        MyWorkMethod(userName, targetNumber);
    };

你能详细说明一下这是如何工作的吗?(特别是“(s, e)”...为什么要声明它们?) - Jeff Meatball Yang
我非常喜欢这个 - 对于我的使用情况,它运行得很好,但更复杂的应用可能会有问题,例如我需要在设置/初始化时访问参数值(用户名和目标号码)。 - Jeff Meatball Yang
1
很高兴能够帮助你(还有一些其他的文字)。 - Ben M
2
我认为这个解决方案的警告是,我们失去了在DoWorkEventArgs e中填充Result或Cancel字段的能力。如果你本来就没有打算使用它们,那就太好了。 - Samik R
1
@Samik R,你不能只是这样保留结果吗:(s,e) => e.Result = MyWorkMethod(userName,targetNumber); - Brad Cunningham

12

使用类型化对象有什么问题吗?

internal class UserArgs
{
    internal string UserName { get; set; }
    internal string TargetNumber { get; set; }
}

var args = new UserArgs() {UserName="Me", TargetNumber="123" };
startCallWorker.RunWorkerAsync(args);

这比我的string[]数组更好,但我仍然不想声明另一个类来传递参数到自己的函数中。在.NET中的许多其他内置处理程序中也会发生这种情况 - 我想我正在寻找一种一致的模式,它不会用无用的包装器类污染我的代码。 - Jeff Meatball Yang
2
C# 4.0有元组(tuple)可以容纳多个参数。请参考我的回答。 - Peter Long

4

使用元组代替已输入的对象。C# 4.0为我们提供了元组功能,可以用元组来保存多个参数,从而无需声明新类。


3

对象可以是列表、数组或类似的容器。只需将您的对象作为某种容器,然后在BackgroundWorker中进行转换。但是,您需要确保始终传入相同类型的对象。


如果库的设计者处理了两个参数,为什么不是三个、四个等等呢?解决方案是处理一个参数,而且这个参数可以是任意复杂度的对象。 - DougN

2
也许可以将lambda函数作为您的对象传递?然后在DoWork处理程序中调用它。
endCallWorker.RunWorkerAsync(new Action( () => DelegatedCallTarget(userName, targetNumber) ));

1
创建一个类来保存所有的参数。
Class MyClass
{
     private string m_Username = string.Empty;
     private int m_Targetnumber;

     public MyClass(){}

     public string Username
     {
         get { return m_Username; }
         set { m_Username = value; }
     }

     public int TargetNumber
     {
         get { return m_TargetNumber; }
         set { m_TargetNumber = value; }
     }
 }



// setup/init:

BackgroundWorker startCallWorker = new BackgroundWorker();
startCallWorker.DoWork += new DoWorkEventHandler(StartCallWorker_DoWork);
...

MyClass thisClass = new MyClass();
thisClass.Username = "abcd";
thisClass.TargetNumber = 1234;
startCallWorker.RunWorkerAsync(thisClass);


// the handler:
private void StartCallWorker_DoWork(object sender, DoWorkEventArgs e)
{
     MyClass args = (MyClass)e.Argument;
     string userName = args.Username;
     string targetNumber = args.TargetNumber;
}

0
为什么不将“one”对象传递为参数数组?你只需要在方法内部将它从对象参数转换回数组即可。

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