2012-06-08 6 views
10

Qualcuno sa di un codice che duplica il modo in cui il DebuggerDisplayAttribute analizza e raccoglie la stringa risultante?Qualsiasi codice che duplica il modo in cui il DebuggerDisplayAttribute genera la stringa risultante?

Vorrei creare un attributo personalizzato che faccia quasi la cosa campione. Simile a "Quando viene colpito un punto di interruzione ..." in cui è possibile utilizzare una variabile all'interno di parentesi graffe, come in "{variabile}".

Gestisco già casi semplici, come "{Nome}", ma qualcosa come "{Foo.Name}" richiede codice di riflessione aggiuntivo con cui ho bisogno di aiuto.

Fondamentalmente, voglio analizzare una stringa utilizzando le regole definite nella documentazione DebuggerDisplayAttribute. Al momento, posso analizzare e risolvere "I am {GetName()}". Ho bisogno di aiuto con qualcosa come "Foo's Name: {Foo.Name}"

+0

Si sta tentando di modificare il comportamento di Visual Studio stesso. Pertanto, mentre è possibile creare facilmente un proprio attributo, è necessario estendere Visual Studio per riconoscerlo e generare report. Anche allora, non sono sicuro che tu possa cambiare il comportamento in quel grado. Se è possibile, questo sarebbe il punto di partenza: http://msdn.microsoft.com/en-us/library/bb161946.aspx – JDB

+0

@ Cyborgx37; No. Voglio duplicare solo la funzionalità. Per analizzare la stringa e raccogliere i valori attraverso la riflessione. – AMissico

+0

Purtroppo non penso che ci sia un modo per farlo, vedi questa domanda correlata: http://stackoverflow.com/questions/2793965/does-there-exists-a-method-to-render-an-object-using -debuggerdisplayattribute Sarebbe bello vedere questa funzionalità esposta nel Framework. Forse potresti richiederlo al momento della connessione, se così lo voterò! – Joe

risposta

2

Sto assumendo che questo è per il proprio uso (squadra). Non l'ho provato personalmente, ma hai guardato le spiegazioni su come personalizzare l'attributo DebuggerDisplay trovato here?

+0

So come funziona l'attributo. Come ho detto, posso gestire metodi o proprietà sull'oggetto principale. Sono le proprietà e i metodi sulle proprietà dell'oggetto principale a cui ho bisogno di ulteriore aiuto. – AMissico

+0

Non stavo suggerendo altro, ma pensavo che non avresti potuto capire che puoi effettivamente (apparentemente) alterare il modo in cui DebuggerDisplayAttribute si espande modificando autoexp.cs. Non stai spiegando nel tuo post esattamente quale funzionalità stai cercando. –

+0

Ah, domanda aggiornata. – AMissico

5

Speriamo che questo codice tutto funzioni ... Ho realizzato una versione non di riflessione di ciò che si sta tentando di fare, utilizzando Microsoft Roslyn e la sua capacità di script C# per eseguire il "codice" nel valore dell'attributo come codice C#.

Per utilizzare questo codice, creare un nuovo progetto C# e utilizzare NuGet per aggiungere un riferimento a Roslyn.

Prima le classi che sto usando per testare, solo così puoi vedere gli attributi che ho provato.

using System.Diagnostics; 

namespace DebuggerDisplayStrings 
{ 
    [DebuggerDisplay("The Value Is {StringProp}.")] 
    public class SomeClass 
    { 
     public string StringProp { get; set; } 
    } 

    [DebuggerDisplay("The Value Is {Foo.StringProp}.")] 
    public class SomeClass2 
    { 
     public SomeClass Foo { get; set; } 
    } 

    [DebuggerDisplay("The Value Is {Seven() - 6}.")] 
    public class SomeClass3 
    { 
     public int Seven() 
     { 
      return 7; 
     } 
    } 
} 

Ora i test (sì tutti questi passa):

using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace DebuggerDisplayStrings 
{ 
    [TestClass] 
    public class DebuggerDisplayReaderTests 
    { 
     [TestMethod] 
     public void CanReadStringProperty() 
     { 
      var target = new SomeClass {StringProp = "Foo"}; 
      var reader = new DebuggerDisplayReader(); 
      Assert.AreEqual("The Value Is Foo.", reader.Read(target)); 
     } 

     [TestMethod] 
     public void CanReadPropertyOfProperty() 
     { 
      var target = new SomeClass2 {Foo = new SomeClass {StringProp = "Foo"}}; 
      var reader = new DebuggerDisplayReader(); 
      Assert.AreEqual("The Value Is Foo.", reader.Read(target)); 
     } 

     [TestMethod] 
     public void CanReadMethodResultAndDoMath() 
     { 
      var target = new SomeClass3(); 
      var reader = new DebuggerDisplayReader(); 
      Assert.AreEqual("The Value Is 1.", reader.Read(target)); 
     } 
    } 
} 

beni Infine, i veri:

using System.Collections.Generic; 
using System.Diagnostics; 
using System.Globalization; 
using System.Text.RegularExpressions; 
using Roslyn.Scripting.CSharp; 

namespace DebuggerDisplayStrings 
{ 
    public class DebuggerDisplayReader 
    { 
     // Get the fully evaluated string representation of the DebuggerDisplayAttribute's value. 
     public string Read(object target) 
     { 
      var debuggerDisplayFormat = GetDebuggerDisplayFormat(target); 
      if(string.IsNullOrWhiteSpace(debuggerDisplayFormat)) 
       return target.ToString(); 
      return EvaluateDebuggerDisplayFormat(debuggerDisplayFormat, target); 
     } 

     // Gets the string off the attribute on the target class, or returns null if attribute not found. 
     private static string GetDebuggerDisplayFormat(object target) 
     { 
      var attributes = target.GetType().GetCustomAttributes(typeof(DebuggerDisplayAttribute), false); 
      return attributes.Length > 0 ? ((DebuggerDisplayAttribute)attributes[0]).Value : null; 
     } 

     // Executes each bracketed portion of the format string using Roslyn, 
     // and puts the resulting value back into the final output string. 
     private string EvaluateDebuggerDisplayFormat(string format, object target) 
     { 
      var scriptingEngine = new ScriptEngine(new[] { GetType().Assembly }); 
      var formatInfo = ExtractFormatInfoFromFormatString(format); 
      var replacements = new List<object>(formatInfo.FormatReplacements.Length); 
      foreach (var codePart in formatInfo.FormatReplacements) 
      { 
       var result = scriptingEngine.Execute(codePart, target); 
       replacements.Add((result ?? "").ToString()); 
      } 
      return string.Format(formatInfo.FormatString, replacements.ToArray()); 
     } 

     // Parse the format string from the attribute into its bracketed parts. 
     // Prepares the string for string.Format() replacement. 
     private static DebuggerDisplayFormatInfo ExtractFormatInfoFromFormatString(string format) 
     { 
      var result = new DebuggerDisplayFormatInfo(); 
      var regex = new Regex(@"\{(.*)\}"); 
      var matches = regex.Matches(format); 
      result.FormatReplacements = new string[matches.Count]; 
      for (var i = matches.Count - 1; i >= 0; i--) 
      { 
       var match = matches[i]; 
       result.FormatReplacements[i] = match.Groups[1].Value; 
       format = format.Remove(match.Index + 1, match.Length - 2).Insert(match.Index+1, i.ToString(CultureInfo.InvariantCulture)); 
      } 
      result.FormatString = format; 
      return result; 
     } 
    } 

    internal class DebuggerDisplayFormatInfo 
    { 
     public string FormatString { get; set; } 
     public string[] FormatReplacements { get; set; } 
    } 
} 

Speriamo che ti aiuta. Era solo circa un'ora e mezza di lavoro, quindi il test unitario non è completo in alcun modo, e sono sicuro che ci siano dei bug da qualche parte, ma dovrebbe essere un buon inizio, se stai bene con il Approccio di Roslyn.

+0

http://blogs.msdn.com/b/visualstudio/archive/2011/10/19/introducing-the-microsoft-roslyn-ctp.aspx – AMissico

+0

http://en.wikipedia.org/wiki/Microsoft_Roslyn – AMissico

+0

http : //www.microsoft.com/en-us/download/details.aspx? id = 27746 – AMissico

Problemi correlati