インスタンス単位でブレークポイントを指定する

今月の MSDN Magazine Online は大漁過ぎて追いかけるのが大変……


任意のインスタンスではなく,特定のインスタンスにのみ適用されるブレークポイントを指定できないか?

というのは今年の MVP サミットのときに id:yaneurao さん発で盛り上がったネタなのですが,酔っていて最後どういう結論に落ち着いたのか今ひとつ記憶があいまいでした.
んで,今月の John Robbins 氏 *1 の記事を読んでいたら,この件に関する記述を見つけたので復習と.

ヒント 79 Gregg Miskelly は、自身のブログですばらしいデバッグ手法を打ち出しました。マネージ コードでは、オブジェクトのアドレスがわからないので、インスタンスごとにブレークポイントを設定するのはほぼ不可能です。しかし Gregg は、インスタンスに対して、オブジェクト Id の作成というすばらしい手法を実行すると、条件付きブレークポイントを this == 1# に設定することにより、インスタンスごとにブレークポイントを設定することができることを指摘しています。筆者もこの手法を使うのが適切だったことはこれまで 100 万回はあったと思われます。

確かにこの機能,(やねうらおさんが主張されていたように) 使えるなら使うべきです.
……だんだん記憶がよみがえってきたような.
とりあえず MSDN Library でちゃんと解説されているようなのでそちらへ Go!

オブジェクト ID

この機能は、Visual Basic には使用できません。

アプリケーションによっては、クラスのインスタンスが数多く作成されます。このようなとき、クラスの特定のインスタンスを区別できるように ID を指定する方法が多くの場合有効です。たとえば、クラスの特定のインスタンスが期待どおりに動作していない場合、または特定のインスタンスが 1 しか含まれないはずのところに複数挿入されている場合などに役に立ちます。

ネイティブのオブジェクト ID

アンマネージ コードをデバッグする場合、アドレスを使用してオブジェクトを識別できます。これは、次の 2 つの理由から重要です。

  • アドレスを使用するだけでオブジェクトを追跡できる。これには、アドレスを使用する次の機能が含まれます。
    • そのアドレスでオブジェクトの値を表示。
    • 等価性のチェック。多くのインスタンスでは、オブジェクトのアドレスは、オブジェクト変数自体と同じ方法で使用できます。
  • オブジェクト (インスタンス) のアドレスを使用して、そのインスタンスのメソッドにブレークポイントを設定できる。
    たとえば、CMyType クラスのインスタンスであるオブジェクトがあり、アドレスは 0xcccccccc とします。次のように、そのインスタンスの aMethod メソッドに関数のブレークポイントを指定できます。
    ((CMyType *) 0xcccccccc)->aMethod

マネージ オブジェクト ID

マネージ コードでは、オブジェクトのアドレスを使用して識別する方法は使用できません。代わりに、共通言語ランタイム (CLR) のデバッグ サービスで生成され、オブジェクトに割り当てられた、オブジェクト ID という整数値を使用します。この数値は、CLRデバッグ サービスで生成された正の整数です。オブジェクト ID 値には、オブジェクトを識別するという以外、重要な役割はありません。

オブジェクト ハンドルは、可変長の 10 進の整数で表示され、その後にシャープ記号 (#) が付きます。先頭にゼロは付きません。たとえば、5# です。ハンドルは、異なるデバッガ データのウィンドウの [値] 列に表示されます。

変数のオブジェクト ID を作成するには、変数を右クリックし、[オブジェクト ID の作成] を選択します。デバッガに、123# のように、シャープ記号 (#) が後ろに付いた数字が表示されます。オブジェクト ID を削除するには、変数を右クリックし、[オブジェクト ID の削除] をクリックします。

ブレークポイントにヒットすると、変数のハンドルを [ウォッチ] ウィンドウに入力できます。オブジェクト ID の値が表示され、他の変数と同様に、展開したり、調べたりできます。

オブジェクト ID を使用して、オブジェクトのメソッドにブレークポイントを設定できます。たとえば、CMyType クラスのインスタンスであるオブジェクトがあり、オブジェクト ID は 5# とします。CMyType クラスには、aMethod メソッドが含まれます。次のように、そのインスタンス 5# の aMethod メソッドに関数のブレークポイントを設定できます。

((CMyType) 5#).aMethod

これでもう明日から使えますね.Get Ready?

*1:Windows のデバッグ技術に興味があってこの人を知らなければモグリさん.名著『.NET&Windowsプログラマのためのデバッグテクニック徹底解説』は,Windows/.NET 開発で必読の一冊ですが,そろそろ在庫が怪しそうなのでお早めに