Da jeg var ung, kunne man i Visual C++ 6.0 selv definere, hvordan typer skulle vises i watch-vinduet ved at rette i en hemmelig tekstfil i notepad. Det er også muligt i VS.NET, men det kræver kode i stedet for konfiguration. Man kan nemlig gøre det vha. DebuggerDisplayAttribute. I modsætning til VC++ løsningen kan man derfor kun ændre visningen for sine egne typer.
Jeg vil her vise, hvordan DebuggerDisplayAttribute bruges. Vi tager udgangspunkt i følgende type:
class MyClass
{
public int Number { get; set; }
public string Text { get; set; }
}
Følgende skærmbillede af watch-vinduet viser standardvisningen for vores type:
Hvis man ønsker at vise noget andet end den ikke specielt sigende tekst "{ConsoleApplication3.MyClass}", er den nemme løsning at override ToString:
public override string ToString()
{
return String.Format("Number={0}, Text=\"{1}\"", Number, Text);
}
Overrides af ToString vil altid blive kaldt af debuggeren i watch-vinduet. Med den metode kan man få vist, hvad man vil - f.eks.:
Hvis man ikke ønsker at override ToString bare for at vise noget pænt ved debugging, er DebuggerDisplayAttribute vejen at gå. Koden kommer til at se således ud:
[DebuggerDisplay("Number={Number}, Text={Text}")]
class MyClass
{
public int Number { get; set; }
public string Text { get; set; }
}
Resultatet er det samme som ved brug af ToString. DebuggerDisplay vil altid blive brugt i stedet for ToString af debuggeren. Bemærk at debuggeren selv indsætter anførselstegn omkring strenge ved brug af DebuggerDisplay.
Som standard viser watch-vinduet alle properties og fields (public såvel som private), når man klikker på '+' ved siden af variabelnavnet. Vha. en anden attribute, DebuggerBrowsable, kan man helt fjerne properties fra visningen:
[DebuggerDisplay("Number={Number}, Text={Text}")]
class MyClass
{
public int Number { get; set; }
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public string Text { get; set; }
}
Det giver følgende visning:
Man har også mulighed for helt at ændre denne visning vha. en tredje attribute, DebuggerTypeProxy:
[DebuggerDisplay("Number={Number}, Text={Text}")]
[DebuggerTypeProxy(typeof(MyClassDebugView))]
class MyClass
{
public int Number { get; set; }
public string Text { get; set; }
internal class MyClassDebugView
{
MyClass c;
public MyClassDebugView(MyClass c)
{
this.c = c;
}
public string NumberAndText { get { return c.Number.ToString() + ", " + c.Text; } }
}
}
Debuggeren kalder constructoren for MyClassDebugView med det objekt af typen MyClass, som bliver vist i watch. Nedenfor er vist, hvordan det kommer til at se ud i watch-vinduet. Bemærk at debuggeren selv tilføjer et raw-view.
