È ansible accedere all’attributo child “DebuggerDisplay” della proprietà?

Stato attuale

Avere due classi:

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

Usandoli:

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

All’interno del debugger, il valore della punta dello strumento che viene visualizzato in a è

Uno = 5, due = {DebuggerDisplayTest.B}

Obbiettivo

Quello che vorrei è qualcosa di simile

Uno = 5, due = ‘Tre = 10’

So che questo potrebbe essere ottenuto sovrascrivendo il metodo ToString() della class B Questo non mi sembra giusto, dal momento che sto scrivendo il codice nella mia applicazione solo per il debug.

So anche che usando una stringa simile a

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

funzionerebbe anche Anche questo non mi sembra giusto, dal momento che richiederebbe che la class A abbia conoscenza della class B

Mi piacerebbe avere più di un modo per “iniettare” il valore di DebuggerDisplay di tipo B per l’istanza di quel tipo in class A

Domanda

È in qualche modo ansible accedere all’attributo DebuggerDisplay di un membro all’interno dell’attributo DebuggerDisplay di una class composita “has-a”?

Aggiornare

Probabilmente, il mio requisito non è ansible secondo questa risposta SO . Forse una buona soluzione sarebbe quella di sovrascrivere ToString in class B e fare un po ‘di if..else e usare la proprietà Debugger.IsAttached per comportarsi diversamente solo all’interno del debugger.

Qualcosa di simile a:

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

Soluzione ansible copiata da OP

Probabilmente, il mio requisito non è ansible secondo questa risposta SO . Forse una buona soluzione sarebbe quella di sovrascrivere ToString in class B e fare un po ‘di if..else e usare la proprietà Debugger.IsAttached per comportarsi diversamente solo all’interno del debugger.

Qualcosa di simile a:

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

[Disclaimer Sono affiliato con OzCode]

È ansible utilizzare la funzione Revoca di OzCode che supporta le informazioni di debug nidificate. Rivela in azione!
Il lato positivo è che non è necessario modificare il codice di produzione e una volta definito per un’istanza, esso verrebbe utilizzato automaticamente per tutte le istanze di quel tipo.

Mettendo insieme alcune cose ho trovato questa soluzione. Ha l’avvertenza che si aspetta di seguire https://blogs.msdn.microsoft.com/jaredpar/2011/03/18/debuggerdisplay-attribute-best-practices/ . Utilizza C # 6 ( compatibile con 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()}"; } 

Avrai bisogno di assicurarti di avere le importazioni corrette per dove ti attacca questo helper in relazione al codice che deve leggere i display del debugger figlio.

 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>.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) ?? ""; debuggerDisplay = value as string ?? value.ToString(); } catch (Exception) { // ignored } return debuggerDisplay ?? $""; } } 

Ritengo che questo sia un giusto equilibrio di purezza e pragmatismo per abbassare l’attrito sul raggiungimento di questo. Se sei meno preoccupato della purezza, potresti rendere pubblico DebuggerDisplay. Preferisco che ReadDebuggerDisplay operi in modo “senza tipo” (evita i vincoli generici e le interfacce che sarebbero necessarie per accedere a DebuggerDisplay pubblicamente).