我现在有一段时间了编写GUI应用程序中有一件事我一直用的都是MethodInvoker + lambda函数做跨线程访问。
从例子中我发现,我总是看到这样的东西:
第1版
if (InvokeRequired)
{
Invoke(new MethodInvoker(() =>
{
Label1.Text = "Foobar";
});
}
else
{
Label1.Text = "Foobar";
}
然而,这会导致代码的重复 - >大坏蛋给我。
那么,有什么问题呢?
第2版
MethodInvoker updateText = new MethodInvoker(() =>
{
Label1.Text = "Foobar";
});
if (InvokeRequired)
{
Invoke(updateText);
}
else
{
updateText();
}
现在我有以下功能:在一个变量捆绑与调用或函数指针在适当的时候调用它。 为2版性能越差明智? 或者是我不好的做法,使用匿名函数呢?
没有什么地方错了...但你可以添加一个扩展方法,使这一切有点更好:
public static void InvokeIfNecessary(this Control control,
MethodInvoker action)
{
if (control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action();
}
}
然后,你可以这样写:
this.InvokeIfNecessary(() => Label1.Text = "Foobar");
更整洁:)
有一个从创建委托时,你并不需要一个很轻微的性能缺陷,但它几乎肯定微不足道-专注于编写干净的代码。
请注意,即使你不想做,你仍然可以使你的变量声明简单在现有的代码:
MethodInvoker updateText = () => Label1.Text = "Foobar";
这是使用一个独立的变量的一个好处-你不需要new MethodInvoker
位来告诉你想要什么类型的委托的lambda表达式...
为2版性能越差明智? 或者是我不好的做法,使用匿名函数呢?
没有第2版比较好,不用担心它的性能问题。 而不是使用匿名函数,你也可以定义一个方法:
public void SetLabelTextToFooBar()
{
Label1.Text = "Foobar";
}
然后:
if (InvokeRequired)
{
Invoke(SetLabelTextToFooBar);
}
else
{
SetLabelTextToFooBar();
}
或者简单地用一个BackgroundWorker的 ,它会自动执行所有回调(如RunWorkerCompleted
和ProgressChanged
,这样你就不需要检查主UI线程) InvokeRequired
。
在做另一种做法:
Invoke((MethodInvoker)delegate
{
Label1.Text = "Foobar";
});