デバッガー表示属性によるデバッグ機能の拡張
デバッガー表示属性を使用すると、開発した型の実行時の動作を指定し、その動作を最もよく理解している開発者が、その型がデバッガーに表示されるときの表示形式を指定することもできます。 さらに、Target プロパティを提供するデバッガー表示属性は、ソース コードに関する知識を持たないユーザーがアセンブリ レベルで適用できます。 DebuggerDisplayAttribute 属性では、デバッガーの変数ウィンドウでの型やメンバーの表示形式を制御できます。 DebuggerBrowsableAttribute 属性では、デバッガーの変数ウィンドウでフィールドやプロパティを表示するかどうか、またその表示形式を決定できます。 DebuggerTypeProxyAttribute 属性では、型の代替型つまりプロキシを指定し、デバッガー ウィンドウでの型の表示形式を変更できます。 プロキシ (代替型) を指定した変数を表示すると、元の型の代わりにプロキシがデバッガー表示ウィンドウに表示されます。 デバッガーの変数ウィンドウには、プロキシ型のパブリック メンバーのみが表示されます。 プライベート メンバーは表示されません。
DebuggerDisplayAttribute の使用
DebuggerDisplayAttribute コンストラクターの引数は 1 つです。この引数は、型のインスタンスの値列に表示される文字列です。 この文字列には、中かっこ ({ と }) を含めることができます。 中かっこで囲まれたテキストは、式として評価されます。 たとえば、次の C# コードでは、正符号 (+) を選択して MyHashtable のインスタンスのデバッガー表示を拡張すると "Count = 4" が表示されます。
[DebuggerDisplay("Count = {count}")]
class MyHashtable
{
public int count = 4;
}
式で参照されるプロパティに適用されている属性は処理されません。 C# コンパイラでは、対象型の現在のインスタンスについて、このような参照に暗黙的にのみアクセスできる一般的な式を使用できます。 この式には制限があり、エイリアス、ローカル、またはポインターへはアクセスできません。 C# コードでは、対象型の現在のインスタンスのみについて、this ポインターに暗黙的にアクセスできる一般的な式を中かっこに囲んで使用できます。
たとえば、C# オブジェクトにオーバーライドされた ToString() がある場合、デバッガーはそのオーバーライドを呼び出し、標準的な {<typeName>}. タグ内のピリオド削除ではなくオーバーライドの結果を表示します。そのため、オーバーライドされた ToString() がある場合、DebuggerDisplayAttribute を使用する必要はありません。 両方を使用すると、DebuggerDisplayAttribute 属性が ToString() オーバーライドよりも優先されます。
DebuggerBrowsableAttribute の使用
デバッガー ウィンドウに表示されるフィールドやプロパティの表示形式を指定するには、DebuggerBrowsableAttribute をフィールドまたはプロパティに適用します。 この属性のコンストラクターは、DebuggerBrowsableState 列挙値のいずれかを受け取ります。この列挙値は、次のいずれかの状態を指定します。
Never は、メンバーがデータ ウィンドウに表示されないことを示します。 たとえば、フィールドの DebuggerBrowsableAttribute にこの値を使用すると、そのフィールドは階層から削除され、型インスタンスの正符号 (+) をクリックして外側の型を展開しても表示されません。
Collapsed は、既定で、メンバーは表示され、展開されないことを示します。 これが既定の動作です。
RootHidden は、メンバー自体は表示されず、そのメンバーが配列やコレクションの場合、その内在オブジェクトが表示されることを示します。
メモ |
---|
DebuggerBrowsableAttribute は、.NET Framework Version 2.0 の Visual Basic ではサポートされません。 |
DebuggerBrowsableAttribute を使用して、後続のプロパティがクラスのデバッグ ウィンドウに表示されないようにするコード例を次に示します。
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public static string y = "Test String";
DebuggerTypeProxy の使用
型のデバッグ ビューを大幅に変更しても、型自体を変更しないときは、DebuggerTypeProxyAttribute 属性を使用します。 DebuggerTypeProxyAttribute 属性は、型の表示プロキシを指定して、開発者が型のビューを調整できるようにする場合に使用します。 DebuggerDisplayAttribute と同様に、この属性はアセンブリ レベルで使用できます。その場合、Target プロパティで、プロキシを使用する型を指定します。 この属性は、その適用先の型内で発生する入れ子にされたプライベート型を指定するために使用することをお勧めします。 型ビューアーをサポートする式エバリュエーターは、型が表示されるときにこの属性をチェックします。 属性が存在する場合、式エバリュエーターは属性の適用対象の型の代わりに表示プロキシ型を使用します。
DebuggerTypeProxyAttribute が存在する場合、デバッガー変数ウィンドウにはプロキシ型のパブリック メンバーのみが表示されます。 プライベート メンバーは表示されません。 データ ウィンドウの動作は、属性拡張ビューによって変更されません。
パフォーマンスへの不必要な影響を避けるために、表示プロキシの属性は、データ ウィンドウ内の型の横にある正符号 (+) をユーザーがクリックするか、または DebuggerBrowsableAttribute 属性を適用することによってオブジェクトが展開されるまで処理されません。 したがって、表示型に属性を適用しないことをお勧めします。 属性は表示型の本体内で適用できるようにします。
DebuggerTypeProxyAttribute を使用して、デバッガー表示プロキシとして使用する型を指定するコード例を次に示します。
[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable : Hashtable
{
private const string TestString =
"This should not appear in the debug window.";
internal class HashtableDebugView
{
private Hashtable hashtable;
public const string TestStringProxy =
"This should appear in the debug window.";
// The constructor for the type proxy class must have a
// constructor that takes the target type as a parameter.
public HashtableDebugView(Hashtable hashtable)
{
this.hashtable = hashtable;
}
}
}
例
説明
次のコード例を Visual Studio 2005 で表示すると、DebuggerDisplayAttribute、DebuggerBrowsableAttribute、DebuggerTypeProxyAttribute の各属性の適用結果を確認できます。
コード
Imports System
Imports System.Collections
Imports System.Diagnostics
Imports System.Reflection
Class DebugViewTest
' The following constant will appear in the debug window for DebugViewTest.
Const TabString As String = " "
' The following DebuggerBrowsableAttribute prevents the property following it
' from appearing in the debug window for the class.
<DebuggerBrowsable(DebuggerBrowsableState.Never)> _
Public Shared y As String = "Test String"
Shared Sub Main()
Dim myHashTable As New MyHashtable()
myHashTable.Add("one", 1)
myHashTable.Add("two", 2)
Console.WriteLine(myHashTable.ToString())
Console.WriteLine("In Main.")
End Sub 'Main
End Class 'DebugViewTest
<DebuggerDisplay("{value}", Name := "{key}")> _
Friend Class KeyValuePairs
Private dictionary As IDictionary
Private key As Object
Private value As Object
Public Sub New(ByVal dictionary As IDictionary, ByVal key As Object, ByVal value As Object)
Me.value = value
Me.key = key
Me.dictionary = dictionary
End Sub 'New
End Class 'KeyValuePairs
<DebuggerDisplay("Count = {Count}"), DebuggerTypeProxy(GetType(MyHashtable.HashtableDebugView))> _
Class MyHashtable
Inherits Hashtable
Private Const TestString As String = "This should not appear in the debug window."
Friend Class HashtableDebugView
Private hashtable As Hashtable
Public Shared TestString As String = "This should appear in the debug window."
Public Sub New(ByVal hashtable As Hashtable)
Me.hashtable = hashtable
End Sub 'New
<DebuggerBrowsable(DebuggerBrowsableState.RootHidden)> _
ReadOnly Property Keys as KeyValuePairs()
Get
Dim nkeys(hashtable.Count) as KeyValuePairs
Dim i as Integer = 0
For Each key As Object In hashtable.Keys
nkeys(i) = New KeyValuePairs(hashtable, key, hashtable(key))
i = i + 1
Next
Return nkeys
End Get
End Property
End Class 'HashtableDebugView
End Class 'MyHashtable
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
class DebugViewTest
{
// The following constant will appear in the debug window for DebugViewTest.
const string TabString = " ";
// The following DebuggerBrowsableAttribute prevents the property following it
// from appearing in the debug window for the class.
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public static string y = "Test String";
static void Main()
{
MyHashtable myHashTable = new MyHashtable();
myHashTable.Add("one", 1);
myHashTable.Add("two", 2);
Console.WriteLine(myHashTable.ToString());
Console.WriteLine("In Main.");
}
}
[DebuggerDisplay("{value}", Name = "{key}")]
internal class KeyValuePairs
{
private IDictionary dictionary;
private object key;
private object value;
public KeyValuePairs(IDictionary dictionary, object key, object value)
{
this.value = value;
this.key = key;
this.dictionary = dictionary;
}
}
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable : Hashtable
{
private const string TestString = "This should not appear in the debug window.";
internal class HashtableDebugView
{
private Hashtable hashtable;
public const string TestString = "This should appear in the debug window.";
public HashtableDebugView(Hashtable hashtable)
{
this.hashtable = hashtable;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePairs[] Keys
{
get
{
KeyValuePairs[] keys = new KeyValuePairs[hashtable.Count];
int i = 0;
foreach(object key in hashtable.Keys)
{
keys[i] = new KeyValuePairs(hashtable, key, hashtable[key]);
i++;
}
return keys;
}
}
}
}
using namespace System;
using namespace System::Collections;
using namespace System::Diagnostics;
using namespace System::Reflection;
ref class HashtableDebugView;
[DebuggerDisplay("{value}", Name = "{key}")]
ref class KeyValuePairs
{
private:
IDictionary^ dictionary;
Object^ key;
Object^ value;
public:
KeyValuePairs(IDictionary^ dictionary, Object^ key, Object^ value)
{
this->value = value;
this->key = key;
this->dictionary = dictionary;
}
};
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(HashtableDebugView::typeid)]
ref class MyHashtable : Hashtable
{
private:
static const String^ TestString = "This should not appear in the debug window.";
internal:
ref class HashtableDebugView
{
private:
Hashtable^ hashtable;
public:
static const String^ TestString = "This should appear in the debug window.";
HashtableDebugView(Hashtable^ hashtable)
{
this->hashtable = hashtable;
}
[DebuggerBrowsable(DebuggerBrowsableState::RootHidden)]
property array<KeyValuePairs^>^ Keys
{
array<KeyValuePairs^>^ get()
{
array<KeyValuePairs^>^ keys = gcnew array<KeyValuePairs^>(hashtable->Count);
IEnumerator^ ie = hashtable->Keys->GetEnumerator();
int i = 0;
Object^ key;
while (ie->MoveNext())
{
key = ie->Current;
keys[i] = gcnew KeyValuePairs(hashtable, key, hashtable[key]);
i++;
}
return keys;
}
}
};
};
public ref class DebugViewTest
{
private:
// The following constant will appear in the debug window for DebugViewTest.
static const String^ TabString = " ";
public:
// The following DebuggerBrowsableAttribute prevents the property following it
// from appearing in the debug window for the class.
[DebuggerBrowsable(DebuggerBrowsableState::Never)]
static String^ y = "Test String";
static void Main()
{
MyHashtable^ myHashTable = gcnew MyHashtable();
myHashTable->Add("one", 1);
myHashTable->Add("two", 2);
Console::WriteLine(myHashTable->ToString());
Console::WriteLine("In Main.");
}
};
int main()
{
DebugViewTest::Main();
}