Visual Studio Visualizer深入解析

Visual Studio的Visualizer工具是开发者在调试过程中的得力助手,它能够帮助开发者以图形化的方式查看对象的内部结构,从而更直观地理解数据。本文将详细介绍Visual Studio Visualizer的背景、使用方法、代码实现以及历史版本信息。

Visual StudioVisualizer是Visual Studio调试器的一部分,它允许开发者在调试过程中查看对象的属性和值。如果对Visual Studio Visualizer不熟悉,建议先阅读。第二部分则介绍了与Entity Framework结合使用的情况,可以在查看。

使用代码

Visual StudioVisualizer中,使用反射来读取列表中的值,并将其传递给Visualizer。这里使用了简单的数据传输对象(DTO):

public class Entity { public Guid Pk = Guid.NewGuid(); public string Name { get; set; } List<EntityProperties> properties; public List<EntityProperties> Properties { get { if (properties == null) properties = new List<EntityProperties>(); return properties; } set { properties = value; } } List<Entity> nestedEntities; public List<Entity> NestedEntities { get { if (nestedEntities == null) nestedEntities = new List<Entity>(); return nestedEntities; } set { nestedEntities = value; } } }

此类包含一个名称、一个属性列表以及一个称为NestedEntities的复杂属性列表。EntityProperties是一个容器,用于存储简单的.NET属性,如字符串、整数等:

public class EntityProperties { public string PropertyName { get; set; } public object Value { get; set; } public string PropertyType { get; set; } }

反射方法遍历列表中的所有实体,并填充一个Entity列表,然后将其传递给Visualizer:

private void WriteObject(object o, Entity currentEntity) { if (o is IEnumerable) { foreach (object element in (IEnumerable)o) { if (element is IEnumerable && !(element is string)) { if (level < depth) { level++; WriteObject(element, currentEntity); level--; } } else WriteObject(element, currentEntity); } } else { // reads the object members MemberInfo[] members = o.GetType().GetMembers( BindingFlags.Public | BindingFlags.Instance); Entity newEntity = new Entity(); newEntity.Name = o.ToString(); // we are only interested in properties and fields foreach (MemberInfo m in members.Where(p => p is FieldInfo || p is PropertyInfo)) { FieldInfo f = m as FieldInfo; PropertyInfo p = m as PropertyInfo; if (f != null || p != null) { Type t = f != null ? f.FieldType : p.PropertyType; // reads the properties values, name value and type EntityProperties property = new EntityProperties(); property.PropertyName = m.Name; property.PropertyType = t.FullName; if (t.IsValueType || t == typeof(string)) { try { // reads the value property.Value = f != null ? f.GetValue(o) : p.GetValue(o, null); newEntity.Properties.Add(property); } catch { } } } } // add to new entity or as a nested entity if (currentEntity == null) entities.Add(newEntity); else currentEntity.NestedEntities.Add(newEntity); // where we read the complex properties until the defined depth if (level < depth) { foreach (MemberInfo m in members.Where(p => p is FieldInfo || p is PropertyInfo)) { FieldInfo f = m as FieldInfo; PropertyInfo p = m as PropertyInfo; if (f != null || p != null) { Type t = f != null ? f.FieldType : p.PropertyType; if (!(t.IsValueType || t == typeof(string))) { try { object value = f != null ? f.GetValue(o) : p.GetValue(o, null); if (value != null) { level++; WriteObject(value, newEntity); level--; } } catch { } } } } } } }

对于列表中的每个条目,都使用递归,因为每个复杂的相关实体都需要被可视化。这个版本仅支持List<>的可视化,但考虑到未来版本的扩展,创建了一个扩展方法:

public static List<Entity> DumpMe(this Object o, int depth = 2) { string filename = System.IO.Path.Combine(Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData), "CodeVisualizer", "CodeVisualizerOptions.xml"); if (File.Exists(filename)) { XDocument doc = XDocument.Load(filename); XElement xe = doc.Descendants("Depth").FirstOrDefault(); if (xe != null) int.TryParse(xe.Value, out depth); } return Dump.ReadObject(o, depth).entities; }

Dump.ReadObject方法简单地调用了上面描述的方法。这里使用了XDocument来读取深度值,这个值可以由用户在Visualizer中持久化。将这个值存储在属性项目中不起作用,因为返回的值总是0,使用XmlSerializer读取文件也返回0,所以XDocument是一个变通方法。

使用Visualizer

在本系列的中,对如何使用Visualizer进行了所有解释。Visualizer以树状视图显示信息,所有复杂属性作为子节点。显示的信息包括属性的名称、值和类型。

可以按名称、值或类型过滤信息,这对于包含大量项目的列表至关重要。过滤可以通过名称、值或类型进行:

还可以更改显示的深度,即显示的复杂属性(子节点)。这个限制是出于性能原因,测试是在不使用深度限制的情况下使用实体框架进行的,Visualizer可能会逐个属性地检索整个数据库!要更改使用的深度,请在深度文本框中更改值并重新启动Visualizer。

对于更详细的操作,可以将数据导出到XML和Excel:

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485