使用不带Invoke的MethodInvoker

我现在正在编写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(); } 

现在我将function捆绑在一个变量中,并在适当时使用Invoke或函数指针调用它。 版本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 ,它将在主UI线程上自动执行所有回调(例如RunWorkerCompletedProgressChanged ),这样您就不需要检查InvokeRequired

这样做的另一种做法:

 Invoke((MethodInvoker)delegate { Label1.Text = "Foobar"; });