Freigeben über


Teilen Sie dem Debugger mit, was mit dem DebuggerDisplay-Attribut angezeigt werden soll (C#, Visual Basic, F#, C++/CLI)

Die DebuggerDisplayAttribute steuert, wie ein Objekt, eine Eigenschaft oder ein Feld in den Fenstern der Debuggervariablen angezeigt wird. Dieses Attribut kann auf Typen (Klassen, Strukturen, Enumerationen, Stellvertretungen) angewendet werden, wird jedoch in der Regel nur auf Klassen und Strukturen angewendet. Wenn sie auf einen Basistyp angewendet wird, gilt das Attribut auch für eine Unterklasse.

Das attribut DebuggerDisplay hat ein einzelnes Argument, bei dem es sich um eine Zeichenfolge handelt, die in der Wertspalte für Instanzen des Typs angezeigt werden soll. Diese Zeichenfolge kann geschweifte Klammern ({ und }) enthalten. Text innerhalb eines Klammerpaars wird als Feld, Eigenschaft oder Methode ausgewertet.

Wenn eine Klasse über eine überschreibene ToString()-Methode verfügt, verwendet der Debugger die überschreibene Methode anstelle der Standardmethode {<typeName>}. Wenn Sie die ToString()-Methode überschrieben haben, verwendet der Debugger die überschriebenen Methode anstelle des Standard-{<typeName>}, und Sie müssen DebuggerDisplaynicht verwenden. Wenn Sie beide Attribute verwenden, hat das Attribut DebuggerDisplay Vorrang vor der überschriebenen ToString()-Methode. Das DebuggerDisplay-Attribut hat auch Vorrang vor der überschriebenen ToString()-Methode in einer Unterklasse.

Ob der Debugger diesen impliziten ToString() Aufruf auswertet, hängt von einer Benutzereinstellung im Dialogfeld Tools/Optionen/Debugging ab.

Wichtig

Wenn das Kontrollkästchen Unformatierte Struktur von Objekten in Variablenfenstern anzeigen im Dialogfeld Tools / Optionen / Debuggen aktiviert ist, wird das DebuggerDisplay Attribut ignoriert.

Anmerkung

Bei systemeigenem Code wird dieses Attribut nur in C++/CLI-Code unterstützt.

In der folgenden Tabelle sind einige mögliche Verwendungsmöglichkeiten des attributs DebuggerDisplay und Beispielausgaben aufgeführt.

Attribut In der Spalte „Wert“ angezeigte Ausgabe
[DebuggerDisplay("x = {x} y = {y}")]

Wird für einen Typ mit Feldern x und yverwendet.
x = 5 y = 18
[DebuggerDisplay("String value is {getString()}")]Parametersyntax kann zwischen Sprachen variieren. Verwenden Sie es daher mit Sorgfalt. String value is [5, 6, 6]

DebuggerDisplay können auch benannte Parameter akzeptieren.

Parameter Zweck
Name, Type Diese Parameter wirken sich auf die Spalten Name und Typ der Variablenfenster aus. (Sie können auf Zeichenfolgen festgelegt werden, die dieselbe Syntax wie der Konstruktor verwenden.) Die Überlastung dieser Parameter oder die falsche Verwendung dieser Parameter kann zu verwirrender Ausgabe führen.
Target, TargetTypeName Gibt den Zieltyp an, wenn das Attribut auf Assemblyebene verwendet wird.

Die autoexp.cs Datei verwendet das DebuggerDisplay-Attribut auf Assemblyebene. Die autoexp.cs Datei bestimmt die Standarderweiterungen, die Visual Studio für .NET-Objekte verwendet. Sie können die autoexp.cs Datei anhand von Beispielen zur Verwendung des DebuggerDisplay-Attributs untersuchen oder die autoexp.cs Datei ändern und kompilieren, um die Standarderweiterungen zu ändern. Stellen Sie sicher, dass Sie die autoexp.cs Datei sichern, bevor Sie sie ändern.

Um autoexp.cs zu erstellen, öffnen Sie eine Entwickler-Eingabeaufforderung für VS2015, und führen Sie die folgenden Befehle aus:

cd <directory containing autoexp.cs>
csc /t:library autoexp.cs

Die Änderungen an autoexp.dll werden in der nächsten Debugsitzung berücksichtigt.

Verwenden von Ausdrücken in DebuggerDisplay

Obwohl Sie einen allgemeinen Ausdruck zwischen den geschweiften Klammern in einem DebuggerDisplay-Attribut verwenden können, wird diese Vorgehensweise nicht empfohlen.

Ein allgemeiner Ausdruck in DebuggerDisplay hat nur für die aktuelle Instanz des Zieltyps impliziten Zugriff auf den this-Zeiger. Der Ausdruck hat keinen Zugriff auf Aliasse, lokale Variablen oder Zeiger. Wenn der Ausdruck auf Eigenschaften verweist, werden Attribute für diese Eigenschaften nicht verarbeitet. Beispielsweise würde der C#-Code [DebuggerDisplay("Object {count - 2}")]Object 6 anzeigen, wenn das Feld count 8 war.

Die Verwendung von Ausdrücken in DebuggerDisplay kann zu folgenden Problemen führen:

  • Die Auswertung von Ausdrücken ist der teuerste Vorgang im Debugger, und der Ausdruck wird jedes Mal ausgewertet, wenn er angezeigt wird. Dies kann zu Leistungsproblemen beim Durchlaufen von Code führen. Beispielsweise kann ein komplexer Ausdruck, der zum Anzeigen der Werte in einer Auflistung oder Liste verwendet wird, sehr langsam sein, wenn die Anzahl der Elemente groß ist.

  • Ausdrücke werden vom Ausdrucksauswerter der Sprache des aktuellen Stapelframes und nicht vom Evaluator der Sprache ausgewertet, in der der Ausdruck geschrieben wurde. Dies kann zu unvorhersehbaren Ergebnissen führen, wenn die Sprachen unterschiedlich sind.

  • Die Auswertung eines Ausdrucks kann den Status der Anwendung ändern. Beispielsweise ändert ein Ausdruck, der den Wert einer Eigenschaft festlegt, den Eigenschaftswert im auszuführenden Code.

    Eine Möglichkeit, die möglichen Probleme der Ausdrucksauswertung zu verringern, besteht darin, eine private Eigenschaft zu erstellen, die den Vorgang ausführt und eine Zeichenfolge zurückgibt. Das DebuggerDisplay-Attribut kann dann den Wert dieser privaten Eigenschaft anzeigen. Im folgenden Beispiel wird dieses Muster implementiert:

[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class MyClass
{
    public int count { get; set; }
    public bool flag { get; set; }
    private string DebuggerDisplay
    {
        get
        {
            return string.Format("Object {0}", count - 2);
        }
    }
}

Der Suffix „,nq“ weist den Ausdrucksauswerter an, die Anführungszeichen zu entfernen, wenn der endgültige Wert angezeigt wird (nq = keine Anführungszeichen).

Beispiel

Das folgende Codebeispiel zeigt, wie sie DebuggerDisplayzusammen mit DebuggerBrowsable und DebuggerTypeProxyverwenden. Bei der Anzeige in einem Variablenfenster des Debuggers (z. B. im Fenster Überwachung) wird dadurch eine Erweiterung erzeugt, die folgendermaßen aussieht:

Name Wert Typ
Schlüssel "drei" Objekt {string}
Wert 3 objekt {int}
[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;
    }

    public object Key
    {
        get { return key; }
        set
        {
            object tempValue = dictionary[key];
            dictionary.Remove(key);
            key = value;
            dictionary.Add(key, tempValue);
        }
    }

    public object Value
    {
        get { return this.value; }
        set
        {
            this.value = value;
            dictionary[key] = this.value;
        }
    }
}

[DebuggerDisplay("{DebuggerDisplay,nq}")]
[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable
{
    public Hashtable hashtable;

    public MyHashtable()
    {
        hashtable = new Hashtable();
    }

    private string DebuggerDisplay { get { return "Count = " + hashtable.Count; } }

    private class HashtableDebugView
    {
        private MyHashtable myhashtable;
        public HashtableDebugView(MyHashtable myhashtable)
        {
            this.myhashtable = myhashtable;
        }

        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
        public KeyValuePairs[] Keys
        {
            get
            {
                KeyValuePairs[] keys = new KeyValuePairs[myhashtable.hashtable.Count];

                int i = 0;
                foreach (object key in myhashtable.hashtable.Keys)
                {
                    keys[i] = new KeyValuePairs(myhashtable.hashtable, key, myhashtable.hashtable[key]);
                    i++;
                }
                return keys;
            }
        }
    }
}