3

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

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();
}
4

2 回答 2

13

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

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

  • :控件存在,但尚未创建他的句柄。在这种情况下,IsDisposed == false,IsHandleCreated == false,但InvokeRequired == false 不管你用什么线程来调用它。如果您在InvokeRequired没有测试(或知道其他方式)是否已创建句柄以及是否已释放控件的情况下相信结果,您可能会意外地导致创建的句柄与错误的线程相关联,这会使您的应用程序崩溃. ( update ) 这种状态仅适用于控件是(或者是其子)其句柄尚未创建的表单的情况。
  • Live:控件存在,它的句柄被创建。这是简单的场景,没什么奇怪的。
  • Disposed:这类似于上面的“新建”状态,但是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没有走控制层次结构,导致更多的灾难机会。

于 2013-04-30T13:39:42.883 回答
0

没有真正的区别。第二个可能会稍微高效一些,因为它IsHandleCreated仅在InvokeRequired == false. InvokeRequired只能true在创建句柄的时候,所以这种情况下不需要调用IsHandleCreated

于 2013-04-30T13:34:50.953 回答