2013-06-25 12 views
9

Aktualny stanCzy możliwy jest dostęp do podrzędnego atrybutu właściwości "DebuggerDisplay"?

Posiadające dwie klasy:

[DebuggerDisplay(@"One = {One}, two = {Two}")] 
public class A 
{ 
    public int One { get; set; } 
    public B Two { get; set; } 
} 

[DebuggerDisplay(@"Three = {Three}")] 
public class B 
{ 
    public int Three { get; set; } 
} 

korzystania z nich:

var a = new A {One = 5, Two = new B {Three = 10}}; 

Wewnątrz debugger, wartość podpowiedź, która jest wyświetlana na a jest

Jeden = 5, dwa = {D ebuggerDisplayTest.B}

bramki

Co chciałbym coś takiego jak

One = 5, dwa = 'Trzy = 10'

wiem to można to osiągnąć, przesłoniwszy metodę ToString() klasy B. To po prostu nie jest w porządku, ponieważ piszę kod w mojej aplikacji tylko do debugowania.

wiem też, że używanie znaków podobny do

[DebuggerDisplay(@"One = {One}, two = 'Three = {Two.Three}'")] 

będzie działać, too. To również nie wydaje mi się właściwe, ponieważ wymagałoby, aby klasa A posiadała wiedzę o klasie B.

Chciałbym mieć więcej możliwości "wstrzyknięcia" wartości DebuggerDisplay typu B do instancji tego typu w klasie A.

Pytanie

Czy jest jakiś sposób możliwe do uzyskania dostępu do atrybut członka DebuggerDisplay wewnątrz atrybutem „ma-a” czeniu klasy DebuggerDisplay?

Aktualizacja

Prawdopodobnie mój wymóg nie jest możliwe, ponieważ za this SO answer. Może dobrym rozwiązaniem byłoby przesłonięcie ToString w klasie B i wykonanie niektórych if..else i użycie Debugger.IsAttached property, aby zachowywać się inaczej tylko wewnątrz debuggera.

Coś jak:

[DebuggerDisplay(@"Three = {Three}")] 
public class B 
{ 
    public int Three { get; set; } 

    public override string ToString() 
    { 
     if (Debugger.IsAttached) 
     { 
      return string.Format(@"Three = {0}", Three); 
     } 
     else 
     { 
      return base.ToString(); 
     } 
    } 
} 
+1

Powiązane: http://stackoverflow.com/questions/8677795/chaining-debuggerdisplay-on-complex- typeses –

Odpowiedz

3

Skopiowane możliwe rozwiązanie z OP

Prawdopodobnie mój wymóg nie jest możliwe zgodnie z tym SO answer. Może dobrym rozwiązaniem byłoby przesłonięcie ToString w klasie B i zrobienie czegoś, jeśli ... i użycie Debugger.IsAttached property, aby zachowywać się inaczej tylko wewnątrz debuggera.

Coś jak:

[DebuggerDisplay(@"Three = {Three}")] 
public class B 
{ 
    public int Three { get; set; } 

    public override string ToString() 
    { 
     if (Debugger.IsAttached) 
     { 
      return string.Format(@"Three = {0}", Three); 
     } 
     else 
     { 
      return base.ToString(); 
     } 
    } 
} 
3

[Zastrzeżone jestem związany z OzCode]

Można użyć OzCode na Reveal feature który obsługuje zagnieżdżone informacje debugowania. Reveal in action! Dodatkową stroną jest to, że nie trzeba zmieniać kodu produkcyjnego, a po zdefiniowaniu go dla instancji będzie on automatycznie używany dla wszystkich wystąpień tego typu.

1

Składając razem kilka rzeczy, znalazłem rozwiązanie. Jest to zastrzeżenie, że oczekuje on podążania za https://blogs.msdn.microsoft.com/jaredpar/2011/03/18/debuggerdisplay-attribute-best-practices/. Używa C# 6 (compatible with Visual Studio 2013)

[DebuggerDisplay("{DebuggerDisplay,nq}")] 
public class B 
{ 
    public int Three { get; set; } 

    private string DebuggerDisplay => $"Three = {Three}"; 
} 

[DebuggerDisplay("{DebuggerDisplay,nq}")] 
public class A 
{ 
    public int One { get; set; } 
    public B Two { get; set; } 

    private string DebuggerDisplay => $"One = {One}, two = {Two.ReadDebuggerDisplay()}"; 
} 

musisz upewnić się, że odpowiednie importu dla gdziekolwiek trzymać tego pomocnika w stosunku do kodu, który trzeba czytać dziecku debugera wyświetlaczy.

public static class ReflectionHelper 
{ 
    // https://stackoverflow.com/a/13650728/37055 
    public static object ReadProperty(
     this object target, 
     string propertyName) 
    { 
     var args = new[] {CSharpArgumentInfo.Create(0, null)}; 
     var binder = Binder.GetMember(0, propertyName, target.GetType(), args); 
     var site = CallSite<Func<CallSite, object, object>>.Create(binder); 
     return site.Target(site, target); 
    } 

    public static string ReadDebuggerDisplay(
     this object target, 
     string propertyName = "DebuggerDisplay") 
    { 
     string debuggerDisplay = null; 
     try 
     { 
      var value = ReadProperty(target, propertyName) ?? "<null object>"; 

      debuggerDisplay = value as string ?? value.ToString(); 
     } 
     catch (Exception) 
     { 
      // ignored 
     } 
     return debuggerDisplay ?? 
       $"<ReadDebuggerDisplay failed on {target.GetType()}[{propertyName}]>"; 
    } 
} 

Czuję, że to całkiem sprawiedliwa równowaga pomiędzy czystością i pragmatyzmem, aby obniżyć tarcia na ten cel. Jeśli mniej interesuje Cię czystość, możesz ustawić wyświetlanie DebuggerDisplay jako publiczne. Wolę, aby ReadDebuggerDisplay działał w sposób "bezklejowy" (unikał ogólnych ograniczeń i interfejsów, które byłyby potrzebne do publicznego dostępu do DebuggerDisplay).

Powiązane problemy