Udoskonalanie debugowania za pomocą atrybutów wyświetlania debugera
Uwaga
Ten artykuł jest specyficzny dla programu .NET Framework. Nie ma zastosowania do nowszych implementacji platformy .NET, w tym .NET 6 i nowszych wersji.
Atrybuty wyświetlania debugera umożliwiają deweloperowi typu, który określa i najlepiej rozumie zachowanie środowiska uruchomieniowego tego typu, aby określić, jak ten typ będzie wyglądał, gdy będzie wyświetlany w debugerze. Ponadto atrybuty wyświetlania debugera, które zapewniają Target
właściwość, mogą być stosowane na poziomie zestawu przez użytkowników bez znajomości kodu źródłowego. Atrybut DebuggerDisplayAttribute określa sposób wyświetlania typu lub elementu członkowskiego w oknach zmiennych debugera. Atrybut DebuggerBrowsableAttribute określa, czy pole lub właściwość jest wyświetlane w oknach zmiennych debugera. Atrybut DebuggerTypeProxyAttribute określa typ zastępczy lub serwer proxy dla typu i zmienia sposób wyświetlania typu w oknach debugera. W przypadku wyświetlania zmiennej, która ma serwer proxy lub typ zastępczy, serwer proxy oznacza oryginalny typ w oknie wyświetlania debugera. W oknie zmiennej debugera są wyświetlane tylko publiczne elementy członkowskie typu serwera proxy. Prywatne elementy członkowskie nie są wyświetlane.
Korzystanie z atrybutu DebuggerDisplayAttribute
Konstruktor DebuggerDisplayAttribute ma jeden argument: ciąg, który ma być wyświetlany w kolumnie wartości dla wystąpień typu. Ten ciąg może zawierać nawiasy klamrowe ({ i }). Tekst w ramach pary nawiasów klamrowych jest obliczany jako wyrażenie. Na przykład poniższy kod języka C# powoduje wyświetlenie znaku "Count = 4", gdy znak plus (+) zostanie wybrany w celu rozwinięcia wyświetlania debugera dla wystąpienia MyHashtable
elementu .
[DebuggerDisplay("Count = {count}")]
class MyHashtable
{
public int count = 4;
}
Atrybuty zastosowane do właściwości, do których odwołuje się wyrażenie, nie są przetwarzane. W przypadku kompilatora języka C# jest dozwolone wyrażenie ogólne, które ma tylko niejawny dostęp do tego odwołania dla bieżącego wystąpienia typu docelowego. Wyrażenie jest ograniczone; nie ma dostępu do aliasów, ustawień lokalnych ani wskaźników. W kodzie języka C# można użyć wyrażenia ogólnego między nawiasami klamrowymi, które mają niejawny dostęp do this
wskaźnika tylko dla bieżącego wystąpienia typu docelowego.
Jeśli na przykład obiekt języka C# ma przesłoniętą ToString()
, debuger wywoła przesłonięcia i wyświetli jego wynik zamiast standardu {<typeName>}.
W związku z tym, jeśli zastąpisz ToString()
element , nie musisz używać polecenia DebuggerDisplayAttribute. Jeśli używasz obu tych opcji, DebuggerDisplayAttribute atrybut ma pierwszeństwo przed ToString()
przesłonięciami.
Używanie atrybutu DebuggerBrowsableAttribute
DebuggerBrowsableAttribute Zastosuj element do pola lub właściwości, aby określić sposób wyświetlania pola lub właściwości w oknie debugera. Konstruktor tego atrybutu przyjmuje jedną z DebuggerBrowsableState wartości wyliczenia, która określa jeden z następujących stanów:
Never wskazuje, że element członkowski nie jest wyświetlany w oknie danych. Na przykład użycie tej wartości dla DebuggerBrowsableAttribute pola w polu powoduje usunięcie pola z hierarchii. Pole nie jest wyświetlane po rozwinięciu otaczającego typu, klikając znak plus (+) dla wystąpienia typu.
Collapsed wskazuje, że element członkowski jest wyświetlany, ale nie jest domyślnie rozwinięty. To jest zachowanie domyślne.
RootHidden wskazuje, że sam element członkowski nie jest wyświetlany, ale jego obiekty składowe są wyświetlane, jeśli jest to tablica lub kolekcja.
Uwaga
Element DebuggerBrowsableAttribute nie jest obsługiwany przez język Visual Basic w programie .NET Framework w wersji 2.0.
Poniższy przykład kodu przedstawia użycie elementu , DebuggerBrowsableAttribute aby zapobiec pojawieniu się właściwości w oknie debugowania dla klasy.
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public static string y = "Test String";
Korzystanie z debugeraTypeProxy
Użyj atrybutu DebuggerTypeProxyAttribute , jeśli musisz znacząco i zasadniczo zmienić widok debugowania typu, ale nie zmienić samego typu. Atrybut DebuggerTypeProxyAttribute służy do określania wyświetlanego serwera proxy dla typu, co umożliwia deweloperowi dostosowanie widoku dla typu. Ten atrybut, taki jak DebuggerDisplayAttribute, może być używany na poziomie zestawu, w takim przypadku Target właściwość określa typ, dla którego będzie używany serwer proxy. Zalecane użycie polega na tym, że ten atrybut określa prywatny typ zagnieżdżony, który występuje w obrębie typu, do którego jest stosowany atrybut. Ewaluator wyrażeń obsługujący przeglądarki typów sprawdza ten atrybut po wyświetleniu typu. Jeśli atrybut zostanie znaleziony, ewaluator wyrażeń zastępuje typ serwera proxy wyświetlania dla typu atrybutu jest stosowany.
DebuggerTypeProxyAttribute Gdy element jest obecny, w oknie zmiennej debugera są wyświetlane tylko publiczne elementy członkowskie typu serwera proxy. Prywatne elementy członkowskie nie są wyświetlane. Zachowanie okna danych nie jest zmieniane przez widoki rozszerzone atrybutów.
Aby uniknąć niepotrzebnych kar za wydajność, atrybuty wyświetlanego serwera proxy nie są przetwarzane, dopóki obiekt nie zostanie rozszerzony, przez użytkownika klikając znak plus (+) obok typu w oknie danych lub za pośrednictwem aplikacji atrybutu DebuggerBrowsableAttribute . W związku z tym zaleca się, aby do typu wyświetlania nie były stosowane żadne atrybuty. Atrybuty mogą i powinny być stosowane w treści typu wyświetlania.
Poniższy przykład kodu przedstawia użycie elementu DebuggerTypeProxyAttribute , aby określić typ, który ma być używany jako serwer proxy wyświetlania debugera.
[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;
}
}
}
Przykład
opis
Poniższy przykład kodu można wyświetlić w programie Visual Studio, aby wyświetlić wyniki stosowania DebuggerDisplayAttributeatrybutów , DebuggerBrowsableAttributei DebuggerTypeProxyAttribute .
Kod
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();
}
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;
}
}
}
}
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
End Class
<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
End Class
<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
<DebuggerBrowsable(DebuggerBrowsableState.RootHidden)> _
ReadOnly Property Keys as KeyValuePairs()
Get
Dim nkeys(hashtable.Count - 1) 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
End Class