c# - IsHandleCreated 和 InvokeRequired 的顺序

标签 c# .net multithreading winforms

我有以下代码,我看到它以两种不同的方式编写。我只是好奇这两种方法中哪一种是更好的做法:

if (this.IsDisposed) return;

if (this.IsHandleCreated)
{
    if (this.InvokeRequired)
    {
        this.Invoke(action);
    }
    else
    {
        action();
    }
}

log.Error("Control handle was not created, therefore associated action was not executed.");

对比

if (this.InvokeRequired)
{
    this.Invoke(action);
}
else    
{
    if (this.IsDisposed) return;

    if (!this.IsHandleCreated)
    {
         log.Error("Control handle was not created, therefore associated action was not executed.");
         return;
    } 

    action();
}

我主要关心的问题源于需要控件具有句柄的操作,而这些操作并不是明确必需的。如果我要做这样的事情,它似乎可以通过确保控件在执行操作之前具有句柄来解决我的问题。想法?

if (control.InvokeRequired)
{
     control.Invoke(action);
}
else
{
    if (control.IsDisposed) return;

    if (!control.IsHandleCreated)
    {
        // Force a handle to be created to prevent any issues.
        log.Debug("Forcing a new handle to be created before invoking action.");
        var handle = control.Handle;
    }

    action();
}

最佳答案

在检查 InvokeRequired 之前,您应该始终检查 IsDisposedIsHandleCreated。这是一个令人抓狂的场景,我花了很多时间来掌握。

以下是控件可能处于的状态:

  • 新建:控件存在,但尚未创建其句柄。在这种情况下,IsDisposed == falseIsHandleCreated == false,但是 InvokeRequired == false 无论您使用什么线程称之为。如果您信任 InvokeRequired 的结果而没有测试(或不知道其他方式)句柄是否已创建以及控件是否已被释放,则可能会意外导致句柄的创建与错误相关联线程,它会使您的应用程序崩溃。 (更新)此状态仅在控件是(或其子项)句柄尚未创建的窗体时才适用。
  • Live:控件存在,其句柄已创建。这是简单的场景,没什么奇怪的。
  • Disposed:这类似于上面的“New”状态,但是 IsDisposed == true。同样,InvokeRequired 会骗你,让你痛苦。

正确的做法是:

if(control.IsDisposed || (!control.IsHandleCreated && !control.FindForm().IsHandleCreated))
{
    // some exceptional condition:
    // handle in whatever way is appropriate for your app
    return;
}

if(control.InvokeRequired)
{
    control.Invoke(action);
}
else
{
    action();
}

附加说明

在 .Net 2.0(和 3.x)中,这更糟糕。 InvokeRequired 现在将遍历控件层次结构以确定是否已创建任何祖先控件的句柄,并验证它是在哪个线程上创建的。但是,如果控件位于从未显示过的窗体上,则同样存在危险。以前(在 2.0 - 3.5 中),InvokeRequired 没有遍历控制层次结构,导致更多的灾难机会。

关于c# - IsHandleCreated 和 InvokeRequired 的顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16300527/

相关文章:

c# - 反序列化以 id 为键的 JSON 对象结构

c# - 为什么我的编码在解码后添加\0?

.net - RSA:在.NET 中使用公钥进行解密?

c# - 使用什么代替 Interlocked.Equals

java - SGE : Parallel Environment for a multithreaded java code

c# - 使用代码调用任务进行单元测试同步方法

c# - HiddenField 的值未更新

c# - 如何将单元测试项目放在与主项目相同的存储库中?

.net - 循环外键。我该如何处理它们?

c# - 为什么调试包括外部库代码