Udostępnij za pomocą


Ulepszanie debugowania za pomocą atrybutów wyświetlania debugera

Uwaga / Notatka

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ą właściwość Target, mogą być stosowane przez użytkowników na poziomie zestawu bez znajomości kodu źródłowego. Atrybut DebuggerDisplayAttribute określa sposób wyświetlania typu lub członka 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 proxy lub zamiennik, proxy zastępuje oryginalny typ w oknie wyświetlania debugera. W oknie zmiennych debugera wyświetlane są tylko publiczne elementy członkowskie typu proxy. Prywatni członkowie nie są wyświetlani.

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 nawiasach klamrowych jest oceniany jako wyrażenie. Na przykład poniższy kod języka C# powoduje wyświetlenie tekstu "Count = 4", gdy symbol plus (+) zostanie wybrany, aby rozwinąć wyświetlanie debugera dla wystąpienia elementu MyHashtable.

[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# dozwolone jest ogólne wyrażenie, które ma tylko niejawny dostęp do tej referencji dla bieżącego wystąpienia typu docelowego. Wyrażenie jest ograniczone; nie ma dostępu do aliasów, zmiennych lokalnych ani wskaźników. W kodzie języka C# można użyć dowolnego wyrażenia w nawiasach klamrowych, które ma niejawny dostęp do wskaźnika this wyłącznie dla bieżącego wystąpienia typu docelowego.

Na przykład, jeśli obiekt języka C# ma przesłoniętą ToString(), debuger wywoła przesłonięcie i wyświetli jego wynik zamiast standardowego {<typeName>}.. Dlatego jeśli przesłoniłeś ToString(), nie musisz używać DebuggerDisplayAttribute. Jeśli używasz obu tych opcji, DebuggerDisplayAttribute atrybut ma pierwszeństwo przed ToString() przesłonięciem.

Używanie atrybutu DebuggerBrowsableAttribute

Zastosuj DebuggerBrowsableAttribute do pola lub właściwości, aby ustalić, jak pole lub właściwość będą wyświetlane 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 nie jest wyświetlany w panelu danych. Na przykład użycie tej wartości dla pola DebuggerBrowsableAttribute powoduje usunięcie tego pola z hierarchii. Pole nie jest wyświetlane, gdy rozwijasz otaczający typ, klikając znak plus (+) przy wystąpieniu tego typu.

  • Collapsed wskazuje, że element jest wyświetlany, ale nie jest domyślnie rozwinięty. Jest to 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 / Notatka

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 następującej po nim w oknie debugowania dla klasy.

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public static string y = "Test String";

Korzystanie z Debugger TypeProxy

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, do którego jest stosowany atrybut, typem proxy wyświetlania.

Gdy DebuggerTypeProxyAttribute jest obecny, w oknie debugera zmiennej wyświetlane są tylko publiczne elementy członkowskie typu proxy. Prywatni członkowie nie są wyświetlani. Zachowanie okna danych nie jest zmieniane przez widoki wzmocnione atrybutami.

Aby uniknąć niepotrzebnych kar wydajnościowych, atrybuty proxy wyświetlania nie są przetwarzane, dopóki obiekt nie zostanie rozszerzony, poprzez kliknięcie przez użytkownika znaku plus (+) obok typu w oknie danych lub poprzez użycie 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 ramach typu wyświetlacza.

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 zobaczyć wyniki stosowania atrybutów DebuggerDisplayAttribute, DebuggerBrowsableAttribute i 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

Zobacz także