2012-06-08 20 views
10

DebuggerDisplayAttribute'un sonuç dizesini nasıl ayrıştırıp topladığını gösteren herhangi bir kod bilen var mı?DebuggerDisplayAttribute'un ortaya çıkan dizeyi nasıl oluşturduğunu kopyalayan herhangi bir kod?

Neredeyse örnek bir şey yapan bir özel özellik oluşturmak istiyorum. "Değişken noktaya vurulduğunda", "{değişken}" deki gibi küme parantez içinde bir değişken kullanabileceğiniz gibi.

"{Name}" gibi basit durumları zaten ele alıyorum, ancak "{Foo.Name}" gibi bir şey, yardıma ihtiyacım olan ek bir yansıma kodu gerektirir.

Temel olarak, DebuggerDisplayAttribute belgelerinde tanımlanan kuralları kullanarak bir dizeyi ayrıştırmak istiyorum. Şu anda "Ben {GetName()}" ı çözümleyebiliyor ve çözebiliyorum. "Foo'nun Adı: {Foo.Name}" gibi bir şeye ihtiyacım var:

+0

Visual Studio'nun davranışını değiştirmeye çalışıyorsunuz. Böylece kendi özniteliğinizi kolayca oluşturabiliyor olsanız da, bunu tanımak ve raporlamak için Visual Studio'yu genişletmeniz gerekir. O zaman bile, davranışı o dereceye kadar değiştirip değiştiremeyeceğinizden emin değilim. Mümkünse, burası başlangıç ​​noktası olacaktır: http://msdn.microsoft.com/en-us/library/bb161946.aspx – JDB

+0

@ Cyborgx37; Hayır. Sadece işlevselliği çoğaltmak istiyorum. Dizeyi ayrıştırmak ve değerleri yansıtma yoluyla toplamak. – AMissico

+0

Maalesef bunu yapmanın bir yolu olduğunu düşünmüyorum, şu soruya bakın: http://stackoverflow.com/questions/2793965/does-there-exists-a-method-to-render-an-object-using -debuggerdisplayattribute Bu işlevselliği Framework'de görmek güzel olurdu. Belki de bağlantı üzerinden talep edebilirsiniz - eğer öyleyse bunun için oy kullanacağım! – Joe

cevap

2

Bunun kendi (ekip) kullanımınız için olduğunu farz ediyorum. Bunu kişisel olarak denemedim, ancak here bulunan DebuggerDisplay özniteliğini nasıl özelleştireceğine ilişkin açıklamalara baktınız mı?

+0

Özniteliğin nasıl çalıştığını biliyorum. Bahsettiğim gibi, ana nesnede yöntemleri veya özellikleri ele alabilirim. Ekstra yardıma ihtiyacım olan ana nesnenin özellikleri üzerindeki özellikleri ve yöntemleri. – AMissico

+0

Başka bir şey önermedim, ama aslında Autobreak.cs dosyasını düzenleyerek DebuggerDisplayAttribute'un genişletme şeklini değiştirebileceğinizi fark etmemiş olabileceğinizi düşündüm. Yayınınızda tam olarak hangi işlevsellik aradığınızı açıklamıyorsunuz. –

+0

Ah, güncellenen soru. – AMissico

5

Umarız bu kod hepsi uyuyor ... Microsoft Roslyn ve C# Scripting özelliğini kullanarak C# kodu olarak öznitelik değerindeki "kodu" çalıştırma yeteneğini kullanarak, yapmaya çalıştığınız şeyin yansımayan bir sürümünü yaptım.

Bu kodu kullanmak için, yeni bir C# projesi yapın ve Roslyn'e başvuru eklemek için NuGet'i kullanın.

İlk olarak test etmek için kullanıyorum sınıfları, denediğim öznitelikleri görebilirsiniz.

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

Şimdi testleri (evet bunların hepsi pas):

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

Son olarak, gerçek eşya: size yardımcı oluyor

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

Umarım. Sadece bir buçuk saatlik bir işti, bu yüzden birim testi herhangi bir yolla tamamlanmadı, ve eminim ki orada bir yerde hatalar var, ama sağlam bir başlangıç ​​olmalı. Roslyn yaklaşımı.

+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

İlgili konular