Udostępnij za pośrednictwem


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 MyHashtableelementu .

[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

Zobacz też