任何code表示复制了DebuggerDisplayAttribute是如何产生的结果字符串? [英] Any code that duplicates how the DebuggerDisplayAttribute generates the resulting string?
问题描述
任何人都知道的任何code表示复制如何使用 DebuggerDisplayAttribute
解析,并收集得到的字符串?
Anyone know of any code that duplicates how the DebuggerDisplayAttribute
parses and gathers the resultant string?
我想创建一个可以接近样品的事情的自定义属性。类同当一个断点被击中......在这里,你可以使用大括号中的变量,如{}变量。
I would like to create a custom attribute that does nearly the sample thing. Similiar to "When a breakpoint is hit..." where you can use a variable within curly braces, as in "{variable}".
我已经处理简单的情况下,如(名称),而像{Foo.Name}需要额外的反射code,我需要帮助。
I already handle simple cases, such as "{Name}", but something like "{Foo.Name}" requires extra reflection code that I need help with.
基本上,我想分析使用 DebuggerDisplayAttribute
文档中定义的规则的字符串。现在,我可以分析和解决我是{的GetName()}。我需要的东西,如Foo的名称:{} Foo.Name帮助
Basically, I want to parse a string using the rules defined in the DebuggerDisplayAttribute
documentation. Currently, I can parse and resolve "I am {GetName()}". I need help with something like "Foo's Name: {Foo.Name}"
推荐答案
希望这code都千篇一律......我做你正在尝试做的,使用Microsoft罗斯林和C#脚本什么是无反射版本能力属性值是C#code。在运行code。
Hopefully this code all fits... I made a non-reflection version of what you are trying to do, using Microsoft Roslyn and its C# Scripting ability to run the "code" in the attribute value as C# code.
要使用code,使一个新的C#项目,并且使用的NuGet添加一个引用到罗斯林。
To use this code, make a new C# project, and use NuGet to add a reference to Roslyn.
首先我使用的类进行测试,只是让你可以看到我试过的属性。
First the classes I'm using to test, just so you can see the attributes I tried.
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;
}
}
}
现在测试(是的,这些全通):
Now the tests (yes these all pass):
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));
}
}
}
最后,真货:
Finally, the real goods:
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; }
}
}
希望这可以帮助你。它是只有大约一小时工作的一半,所以单元测试是不完整的以任何方式,我敢肯定里面还有虫子的地方,但它应该是一个良好的开端,如果你是用OK罗斯林的方法。
Hopefully that helps you out. It was only about an hour and a half of work, so the unit testing isn't complete by any means, and I'm sure there are bugs in there somewhere, but it should be a solid start, if you are OK with the Roslyn approach.
这篇关于任何code表示复制了DebuggerDisplayAttribute是如何产生的结果字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!