今天在研究Asp.net Core中Routing部分时,发现了以下的代码
1 2 3 4 5 6 7 8 9 10 11 12 |
[DebuggerDisplay("{DebuggerToString()}")] public class TemplateSegment { public bool IsSimple => Parts.Count == 1; public List<TemplatePart> Parts { get; } = new List<TemplatePart>(); internal string DebuggerToString() { return string.Join(string.Empty, Parts.Select(p => p.DebuggerToString())); } } |
这里通过DebuggerDisplay的方式,使得在调试器的监视界面中,会直接显示List中所有元素的值,而不需要展开这个变量进行查看。
经过查阅文档,开发者可以通过增加一些特性,来优化自己的类型在调试器中的调试体验。在VS下支持的特性,主要有以下几种:
首先是DebuggerDisplayAttribute(string),它改变的是在调试界面中该变量显示的值,如下图所示:
它需要一个字符串作为参数,代表“值”栏将要显示的东西。与插补字符串类似,用大括号{}包裹住的部分都会在运行时求值,以及替换到相应位置。如变量Count=1时$“Count = {Count}”实际上为“Count = 1”。下面是一段示例代码,取得的效果为上图的x变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * 访问对象的属性,调用对象的方法都是可以的! */ [DebuggerDisplay("{ToString()},{Count},{lst.Count}")] public class Test2 { private int Count = 0; public List<int> lst = new List<int>(); public override string ToString() { return "Nyan"; } } |
然后是DebuggerBrowsableAttribute(DebuggerBrowsableState),它可以控制一个变量在调试视图中是否使用。内部的枚举变量有三种取值
- Never – 不显示
- Collapsed – 显示(默认值)
- RootHidden – 变量本身不显示,但是变量内部的所有成员将会提升到同级别显示。常用于List之类的列表。
最后是DebuggerTypeProxyAttribute,当面对一些比较复杂的,如果只显示对象本身无法得到有效信息的情况下,这个特性使你可以以原对象为基础,构建一个专门的对象,在调试视图中显示。具体可以参考以下的例子代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
//设置Base64StringListProxy为这个类的对象在调试视图中实际显示的对象 [DebuggerTypeProxy(typeof(Base64StringListProxy))] [DebuggerDisplay("{" + nameof(DebuggerToString) + "()}")] public class Base64StringList { internal class Base64StringListProxy { //这个对象不会在调试视图中显示 [DebuggerBrowsable(DebuggerBrowsableState.Never)] public Base64StringList sourceList; public List<string> Strings; //需要有一个参数为要代理的类型的构造函数 public Base64StringListProxy(Base64StringList list) { Strings = list.Strings.Select(Base64Decode).ToList(); sourceList = list; } } //里面列表的成员直接在Base64StringList一级列出了。 [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public List<string> Strings = new List<string>(); protected string DebuggerToString() { return string.Join(',', Strings.Select(Base64Decode)); } public static string Base64Decode(string base64EncodedData) { var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData); return System.Text.Encoding.UTF8.GetString(base64EncodedBytes); } public static string Base64Encode(string plainText) { var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); return System.Convert.ToBase64String(plainTextBytes); } } //测试代码 class Program { static void Main(string[] args) { Base64StringList str = new Base64StringList(); str.Strings.Add(Base64StringList.Base64Encode("喵")); str.Strings.Add(Base64StringList.Base64Encode("呜")); str.Strings.Add(Base64StringList.Base64Encode("喵")); str.Strings.Add(Base64StringList.Base64Encode("呜")); Test2 w = new Test2(); Debugger.Break();//此处断点 } } |
以上的Base64StringList,是一个内部以Base64形式存储字符串数据的容器,因为无法直接理解Base64编码,这里通过调试器特性的扩展,使得在调试视图观看时会自动进行解码。通过Base64StringListProxy的代理(需要有以Base64StringList为参数的构造函数),在调试视图中实际显示的是这个类的对象的Strings变量,也就是在构造函数中进行解码后的字符串。同时Base64StringList对象的值,也显示的是解码后列表中的各个成员。下面是实际在调试界面的效果:
其中,Raw View 是不通过 Proxy 查看的该对象的变量信息。可见,sourceList没有出现在列表中,Strings中的元素也都是转回原编码的文本。值得注意的是,Proxy与原对象中的Strings变量,有一个是设置成HideRoot的,在Raw View中直接显示出了列表的成员。
目前还没有测试在MonoDevelop中的有效性,如果有效,相信对于Unity开发的调试也是大有好处的(不过人家也可以直接在GameObject里看啦…?)
PS:不管怎么样还是要把自己学的东西说一下吧…?
PS2:f7(eiki)喜欢w!
PS3: