3

次のコードがあり、2 つの異なる方法で記述されているのを見てきました。私は、2つの方法のどちらがより良い方法であるかに興味があります:

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

をチェックする前に、常にIsDisposedとの両方をチェックする必要があります。これは、私が何時間もかけて習得した気が狂うようなシナリオです。IsHandleCreatedInvokeRequired

コントロールの状態は次のとおりです。

  • New : コントロールは存在しますが、そのハンドルは作成されていません。この場合しかしIsDisposed == falseどのスレッドを使用して呼び出すかは関係ありません。ハンドルが作成されたかどうか、およびコントロールが破棄されたかどうかをテストせずに (または他の方法を知らずに)結果を信頼すると、間違ったスレッドに関連付けられたハンドルが誤って作成され、アプリがクラッシュする可能性があります。 . ( update ) この状態は、コントロールがまだハンドルを作成されていないフォーム (またはフォームの子) である場合にのみ適用されます。IsHandleCreated == falseInvokeRequired == 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、制御階層をたどらなかったため、災害の可能性が高くなりました。

于 2013-04-30T13:39:42.883 に答える
0

実際の違いはありません。2 番目の方法はIsHandleCreatedInvokeRequired == false. InvokeRequiredハンドルが作成されたときにのみ使用できるtrueため、この場合は呼び出す必要はありませんIsHandleCreated

于 2013-04-30T13:34:50.953 に答える