Dela via


Tala om för felsökaren vad som ska visas med hjälp av attributet DebuggerDisplay (C#, Visual Basic, F#, C++/CLI)

DebuggerDisplayAttribute styr hur ett objekt, en egenskap eller ett fält visas i felsökarvariabelns fönster. Det här attributet kan tillämpas på typer (klasser, structs, uppräkningar, ombud), men tillämpas vanligtvis endast på klasser och structs. Om det tillämpas på en bastyp gäller attributet även för en underklass.

Attributet DebuggerDisplay har ett enda argument, vilket är en sträng som ska visas i värdekolumnen för instanser av typen. Den här strängen kan innehålla klammerparenteser ({ och }). Text inom ett par klammerparenteser utvärderas som ett fält, en egenskap eller en metod.

Om en klass har en åsidosatt ToString()-metod använder felsökaren den åsidosatta metoden i stället för standardmetoden {<typeName>}. Om du har åsidosatt metoden ToString() använder felsökaren den åsidosatta metoden i stället för standardmetoden {<typeName>}och du behöver inte använda DebuggerDisplay. Om du använder båda har attributet DebuggerDisplay företräde framför den åsidosatta metoden ToString(). Attributet DebuggerDisplay har också företräde framför den åsidosatta metoden ToString() i en underklass.

Om felsökningsprogrammet utvärderar det här implicita ToString()-anropet beror på en användarinställning i dialogrutan Verktyg/Alternativ/Felsökning.

Viktig

Om kryssrutan Visa rå struktur för objekt i variabler i windows är markerad i dialogrutan Verktyg/Alternativ/Felsökning ignoreras attributet DebuggerDisplay.

Not

För intern kod stöds det här attributet endast i C++/CLI-kod.

I följande tabell visas några möjliga användningar av attributet DebuggerDisplay och exempelutdata.

Attribut Utdata som visas i kolumnen Värde
[DebuggerDisplay("x = {x} y = {y}")]

Används för en typ med fält x och y.
x = 5 y = 18
[DebuggerDisplay("String value is {getString()}")]Parametersyntax kan variera mellan olika språk. Därför bör du använda den med försiktighet. String value is [5, 6, 6]

DebuggerDisplay kan också acceptera namngivna parametrar.

Parametrar Avsikt
Name, Type Dessa parametrar påverkar kolumnerna Name och Type i variabelfönstren. (De kan ställas in på strängar med samma syntax som konstruktorn.) Att överanvända dessa parametrar eller använda dem felaktigt kan orsaka förvirrande utdata.
Target, TargetTypeName Anger måltypen när attributet används på sammansättningsnivå.

Autoexp.cs-filen använder attributet DebuggerDisplay på sammansättningsnivå. Den autoexp.cs filen bestämmer standardexpansioner som Visual Studio använder för .NET-objekt. Du kan undersöka autoexp.cs-filen för exempel på hur du använder attributet DebuggerDisplay, eller så kan du ändra och kompilera autoexp.cs-filen för att ändra standardexpansionerna. Se till att säkerhetskopiera filen autoexp.cs innan du ändrar den.

Skapa autoexp.cs genom att öppna en kommandotolk för utvecklare för VS2015 och köra följande kommandon

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

Ändringarna i autoexp.dll hämtas i nästa felsökningssession.

Använda uttryck i DebuggerDisplay

Även om du kan använda ett allmänt uttryck mellan klammerparenteserna i ett DebuggerDisplay-attribut rekommenderas inte den här metoden.

Ett generellt uttryck i DebuggerDisplay har implicit åtkomst till pekaren this endast för den nuvarande instansen av måltypen. Uttrycket har ingen åtkomst till alias, lokala platser eller pekare. Om uttrycket refererar till egenskaper bearbetas inte attribut för dessa egenskaper. C#-koden [DebuggerDisplay("Object {count - 2}")] skulle till exempel visa Object 6 om fältet count var 8.

Att använda uttryck i DebuggerDisplay kan leda till följande problem:

  • Att utvärdera uttryck är den dyraste åtgärden i felsökningsprogrammet och uttrycket utvärderas varje gång det visas. Detta kan orsaka prestandaproblem när du stegar igenom koden. Till exempel kan ett komplext uttryck som används för att visa värdena i en samling eller lista vara mycket långsamt när antalet element är stort.

  • Uttryck utvärderas av uttrycksutvärderaren för språket i den aktuella stackramen och inte av utvärderaren av språket där uttrycket skrevs. Detta kan orsaka oförutsägbara resultat när språken skiljer sig åt.

  • Utvärdering av ett uttryck kan ändra programmets tillstånd. Ett uttryck som till exempel anger värdet för en egenskap ändrar egenskapsvärdet när koden körs.

    Ett sätt att minska eventuella problem med uttrycksutvärdering är genom att skapa en privat egenskap som utför åtgärden och returnerar en sträng. Attributet DebuggerDisplay kan sedan visa värdet för den privata egenskapen. I följande exempel implementeras det här mönstret:

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

Suffixet "nq" instruerar uttrycksutvärderaren att ta bort citattecknarna när det slutliga värdet visas (nq = inga citattecken).

Exempel

I följande kodexempel visas hur du använder DebuggerDisplaytillsammans med DebuggerBrowsable och DebuggerTypeProxy. När det visas i ett fönster med felsökningsvariabler, till exempel fönstret Watch, skapas en expansion som ser ut så här:

Namn Värde typ
Nyckel "tre" objektet {string}
Värde 3 objektet {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;
            }
        }
    }
}