4

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

现在,我将功能捆绑在一个变量中,并在适当时使用 Invoke 或作为函数指针调用它。版本 2 性能更差吗?或者我为此使用匿名函数是不好的做法?

4

3 回答 3

10

没什么问题...但是您可以添加一个扩展方法以使其变得更好:

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 表达式你想要什么类型的委托......

于 2012-08-14T07:38:09.417 回答
2

另一种做法:

Invoke((MethodInvoker)delegate 
{
     Label1.Text = "Foobar";
});
于 2013-04-23T07:54:04.300 回答
2

版本 2 性能更差吗?或者我为此使用匿名函数是不好的做法?

没有版本 2 更好,不用担心它的性能问题。除了使用匿名函数,您还可以定义一个方法:

public void SetLabelTextToFooBar()
{
    Label1.Text = "Foobar";
}

接着:

if (InvokeRequired)
{
    Invoke(SetLabelTextToFooBar);
}
else
{
    SetLabelTextToFooBar();
}

或者简单地使用一个BackgroundWorker,它会在主 UI 线程上自动执行所有回调(例如RunWorkerCompletedProgressChanged),这样您就不需要检查InvokeRequired.

于 2012-08-14T07:35:26.547 回答