使用C#和反射打印完整对象图

chu*_*h97 1 c# reflection

我有一个compex对象

class A
{
 int Field1;
 int field2;
 property ClassB ClassB;
 property classC classC;
 etc etc....

}
Run Code Online (Sandbox Code Playgroud)

我想用反射打印完整的对象图.有什么好的代码吗?

gat*_*ich 9

一种极简主义的替代方案,能够以可读格式显示复杂对象:

public static string Dump(object o, string name = "", int depth = 3)
{
    try
    {
        var leafprefix = (string.IsNullOrWhiteSpace(name) ? name : name + " = ");

        if (null == o) return leafprefix + "null";

        var t = o.GetType();
        if (depth-- < 1 || t == typeof (string) || t.IsValueType)
            return  leafprefix + o;

        var sb = new StringBuilder();
        var enumerable = o as IEnumerable;
        if (enumerable != null)
        {
            name = (name??"").TrimEnd('[', ']') + '[';
            var elements = enumerable.Cast<object>().Select(e => Dump(e, "", depth)).ToList();
            var arrayInOneLine = elements.Count + "] = {" + string.Join(",", elements) + '}';
            if (!arrayInOneLine.Contains(Environment.NewLine)) // Single line?
                return name + arrayInOneLine;
            var i = 0;
            foreach (var element in elements)
            {
                var lineheader = name + i++ + ']';
                sb.Append(lineheader).AppendLine(element.Replace(Environment.NewLine, Environment.NewLine+lineheader));
            }
            return sb.ToString();
        }
        foreach (var f in t.GetFields())
            sb.AppendLine(Dump(f.GetValue(o), name + '.' + f.Name, depth));
        foreach (var p in t.GetProperties())
            sb.AppendLine(Dump(p.GetValue(o, null), name + '.' + p.Name, depth));
        if (sb.Length == 0) return leafprefix + o;
        return sb.ToString().TrimEnd();
    }
    catch
    {
        return name + "???";
    }
}
Run Code Online (Sandbox Code Playgroud)


hoo*_*cus 6

因为它编译,我有点像我的.我已经将它实现为一系列扩展方法和静态内容,因此将它放在项目中的某个静态类中,一旦包含包含静态类的命名空间,扩展方法将立即可用.以下是您使用它的方式:

myObject.PrintGraph();
Run Code Online (Sandbox Code Playgroud)

它将递归地一直向下遍历图形,直到它找到可以转换为Convert.ToString()的东西,然后它将Debug.Print输出到你的即时窗口.这是一些示例输出:

TopLevelProperty: value //Member of myObject
     MyEnumerableProperty: MyItemProperty: value //A property from an object in myObject
          MyEnumerableProperty: MySubEnumerableProperty: MyItemProperty: value //& so on
Run Code Online (Sandbox Code Playgroud)

但它只打印公共属性.

这是PrintGraph方法:

/// <summary>
/// Prints the graph of this object using Debug.Print.
/// </summary>
/// <param name="o">This object.</param>
/// <param name="prefix">Optional text to prepend to all lines printed by this method.
/// </param>
public static void PrintGraph(this object o, string prefix = "")
{
   Type t = o.GetType(); if (prefix != "") prefix = "     " + prefix;

   foreach (PropertyInfo p in t.GetProperties())
      if (p.PropertyType.IsConvertible()) Debug.Print(prefix + p.Name + ": " +
         Convert.ToString(p.GetValue(o, null)));
      else if (p.PropertyType.IsEnumerable())
         foreach (object sub in (IEnumerable)p.GetValue(o, null)) 
            PrintGraph(sub, prefix + p.Name + ": ");
      else if (p.SimpleGetter()) 
         PrintGraph(p.GetValue(o, null), prefix + p.Name + ": ");
   if (t.IsEnumerable()) foreach (object sub in (IEnumerable)o) PrintGraph(sub);
}
Run Code Online (Sandbox Code Playgroud)

以下是使其运行所需的基础设施:

internal static Type[] ConvertibleTypes = {typeof(bool), typeof(byte), typeof(char),
   typeof(DateTime), typeof(decimal), typeof(double), typeof(float), typeof(int), 
   typeof(long), typeof(sbyte), typeof(short), typeof(string), typeof(uint), 
   typeof(ulong), typeof(ushort)};

/// <summary>
/// Returns true if this Type matches any of a set of Types.
/// </summary>
/// <param name="type">This type.</param>
/// <param name="types">The Types to compare this Type to.</param>
public static bool In(this Type type, params Type[] types) 
{ 
   foreach (Type t in types) if (t.IsAssignableFrom(type)) return true; return false; 
}

/// <summary>
/// Returns true if this Type is one of the types accepted by Convert.ToString() 
/// (other than object).
/// </summary>
public static bool IsConvertible(this Type t) { return t.In(ConvertibleTypes); }

/// <summary>
/// Gets whether this type is enumerable.
/// </summary>
public static bool IsEnumerable(this Type t) 
{ 
   return typeof(IEnumerable).IsAssignableFrom(t); 
}

/// <summary>
/// Returns true if this property's getter is public, has no arguments, and has no 
/// generic type parameters.
/// </summary>
public static bool SimpleGetter(this PropertyInfo info) 
{ 
   MethodInfo method = info.GetGetMethod(false); 
   return method != null && method.GetParameters().Length == 0 && 
      method.GetGenericArguments().Length == 0; 
}
Run Code Online (Sandbox Code Playgroud)