是invokerrequired必需的

本文关键字:invokerrequired | 更新日期: 2023-09-27 18:08:21

我的同事喜欢这样做

if (!listbox1.InvokeRequired)
    listbox1.Items.Add(Container.error_message);
else
    listbox1.Invoke((MethodInvoker)delegate
    {
        listbox1.Items.Add(Container.error_message);
    });

为什么他必须检查invokerequired ?只使用这个语句会更好吗?

    listbox1.Invoke((MethodInvoker)delegate
    {
        listbox1.Items.Add(Container.error_message);
    });

是invokerrequired必需的

如果你确信一个特定的路由可以只有被回调线程到达,那么我倾向于同意你的观点——不是为了避免Invoke,而是为了避免任何重复。如果路径可以从多个路由到达,最好有检查,以避免在非线程情况下的任何开销,但是:重构,使每个代码路径知道它在做什么(只是调用一个实用程序方法)可能是更好的,即UI线程只调用Foo(),而作为工作线程使用Invoke/MethodInvoker调用Foo()

如果您确定该方法将从非gui线程调用,那么使用invokerrequiredd是没有意义的。

此外,您可以将listbox1.Items.Add(Container.error_message);放入一个方法(DRY -不要重复)。这个方法可以在GUI中调用,而不需要调用,可以在后台线程中调用。

最后,(如果有的话)通常的模式是这样的:
void AddMessageToListBox(String message)
{
    if (listbox1.InvokeRequired)
    {
        listbox1.Invoke((Action<String>)AddMessageToListBox, message);
        return;
    }
    listbox1.Items.Add(message);
}

InvokeRequired检查使代码在GUI线程(执行第一个if块)和非GUI线程(块的第二部分)运行时都能工作。

它看起来有点复杂,但如果通过设计代码可以由任何一个线程运行,它是有意义的,至少Invoke将是必要的。就我所记得的,您可以选择只按照您的建议使用Invoke,它也可以在GUI线程运行时工作,但它可能效率稍低。您可能会认为这是微优化,但我建议您简单地测试两种情况下会发生什么以及它消耗了多少时间。

    // Generic delegate for cross thread processing
    private void SetProperty<T>(Control ctrl, string propertyName, T propertyValue)
    {
        if (this.InvokeRequired)
            ctrl.Invoke((Action<Control, string, T>)SetProperty, ctrl, propertyName, propertyValue);
        else
        {
            var property = ctrl.GetType().GetProperty(propertyName);
            property.SetValue(ctrl, propertyValue);
        }
    }
    public object DataSource
    {
        set
        {
            SetProperty(treeView, "DataSource", value);
        }
    }