Sdílet prostřednictvím


Řekněte ladicímu programu, co se má zobrazit pomocí atributu DebuggerDisplay (C#, Visual Basic, F#, C++/CLI).

DebuggerDisplayAttribute řídí způsob zobrazení objektu, vlastnosti nebo pole v oknech proměnných ladicího programu. Tento atribut lze použít pro typy (třídy, struktury, výčty, delegáty), ale obvykle se používá pouze pro třídy a struktury. Pokud je použit u základního typu, atribut se vztahuje také na podtřídu.

Atribut DebuggerDisplay má jeden argument, což je řetězec, který se má zobrazit ve sloupci hodnot pro instance typu. Tento řetězec může obsahovat složené závorky ({ a }). Text v rámci dvojice složených závorek se vyhodnotí jako pole, vlastnost nebo metoda.

Pokud má třída přepsanou metodu ToString(), ladicí program používá tuto přepsanou metodu místo výchozí metody {<typeName>}. Proto pokud jste přepsali metodu ToString(), ladicí program používá přepsánou metodu místo výchozí {<typeName>}a nemusíte používat DebuggerDisplay. Pokud použijete obojí, má atribut DebuggerDisplay přednost před přepsánou metodou ToString(). Atribut DebuggerDisplay má také přednost před přepsánou metodou ToString() v podtřídě.

Zda ladicí program vyhodnotí toto implicitní volání ToString(), závisí na nastavení uživatele v dialogovém okně Nástroje / Možnosti / Ladění.

Důležitý

Pokud je zaškrtnuté políčko Zobrazit nezpracovanou strukturu objektů v oknech proměnných v dialogovém okně Nástroje / Možnosti / Ladění, bude atribut DebuggerDisplay ignorován.

Poznámka

Pro nativní kód je tento atribut podporován pouze v kódu C++/CLI.

Následující tabulka uvádí některé možné použití atributu DebuggerDisplay a ukázkových výstupů.

Atribut Výstup zobrazený ve sloupci Hodnota
[DebuggerDisplay("x = {x} y = {y}")]

Používá se u typu s poli x a y.
x = 5 y = 18
[DebuggerDisplay("String value is {getString()}")]Syntaxe parametru se může mezi jazyky lišit. Proto ho používejte opatrně. String value is [5, 6, 6]

DebuggerDisplay mohou také přijímat pojmenované parametry.

Parametry Účel
Name, Type Tyto parametry ovlivňují Název a Typ sloupců oken proměnných. (Mohou být nastaveny na řetězce pomocí stejné syntaxe jako konstruktor.) Nadměrné využití těchto parametrů nebo jejich nesprávné použití může způsobit matoucí výstup.
Target, TargetTypeName Určuje cílový typ při použití atributu na úrovni sestavení.

Soubor autoexp.cs používá atribut DebuggerDisplay na úrovni sestavení. Soubor autoexp.cs určuje výchozí rozšíření, která sada Visual Studio používá pro objekty .NET. V souboru autoexp.cs můžete prozkoumat příklady použití atributu DebuggerDisplay nebo můžete upravit a zkompilovat soubor autoexp.cs a změnit výchozí rozšíření. Před úpravou nezapomeňte zálohovat soubor autoexp.cs.

Pokud chcete sestavit autoexp.cs, otevřete vývojářský příkazový řádek pro VS2015 a spusťte následující příkazy.

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

Změny autoexp.dll se projeví v další relaci ladění.

Použití výrazů v DebuggerDisplay

I když můžete použít obecný výraz mezi složenými závorkami v atributu DebuggerDisplay, tento postup se nedoporučuje.

Obecný výraz v DebuggerDisplay má implicitní přístup k ukazateli this pouze pro aktuální instanci cílového typu. Výraz nemá přístup k aliasům, lokálním proměnným ani ukazatelům. Pokud výraz odkazuje na vlastnosti, atributy těchto vlastností se nezpracují. Například C# kód [DebuggerDisplay("Object {count - 2}")] se zobrazí jako Object 6, pokud pole count má hodnotu 8.

Použití výrazů v DebuggerDisplay může vést k následujícím problémům:

  • Vyhodnocení výrazů je nejnákladnější operací v ladicím programu a výraz se vyhodnocuje při každém zobrazení. To může způsobit problémy s výkonem při procházení kódu. Například složitý výraz, který se používá k zobrazení hodnot v kolekci nebo seznamu, může být velmi pomalý, pokud je počet prvků velký.

  • Výrazy se vyhodnocují vyhodnocovačem výrazů jazyka aktuálního rámce zásobníku, nikoli vyhodnocovačem jazyka, ve kterém byl výraz napsán. To může způsobit nepředvídatelné výsledky, pokud se jazyky liší.

  • Vyhodnocení výrazu může změnit stav aplikace. Například výraz, který nastaví hodnotu vlastnosti, změní hodnotu vlastnosti v prováděcím kódu.

    Jedním ze způsobů, jak snížit možné problémy vyhodnocení výrazu, je vytvoření privátní vlastnosti, která provádí operaci a vrací řetězec. Atribut DebuggerDisplay pak může zobrazit hodnotu této privátní vlastnosti. Následující příklad implementuje tento vzor:

[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);
        }
    }
}

Přípona ",nq" říká vyhodnocovači výrazů, aby při zobrazení konečné hodnoty odebral uvozovky (nq = žádné uvozovky).

Příklad

Následující příklad kódu ukazuje, jak používat DebuggerDisplay, společně s DebuggerBrowsable a DebuggerTypeProxy. Při zobrazení v okně proměnných ladicího programu, jako je okno Watch, vygeneruje rozšíření, které vypadá následovně:

název hodnota typ
Klíč "tři" object {string}
Hodnota 3 object {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;
            }
        }
    }
}