任何code表示复制了DebuggerDisplayAttribute是如何产生的结果字符串? [英] Any code that duplicates how the DebuggerDisplayAttribute generates the resulting string?

查看:103
本文介绍了任何code表示复制了DebuggerDisplayAttribute是如何产生的结果字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任何人都知道的任何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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆