我有一个compex对象
class A
{
int Field1;
int field2;
property ClassB ClassB;
property classC classC;
etc etc....
}
我想使用反射打印完整的对象图。那里有什么好的代码?
答案 0 :(得分:8)
一种极简主义的替代方案,能够以可读格式显示复杂对象:
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 + "???";
}
}
答案 1 :(得分:6)
我有点像我的,因为它编译。我已经将它实现为一系列扩展方法和静态内容,因此将它放在项目中的某个静态类中,一旦包含包含静态类的命名空间,扩展方法将立即可用。以下是您使用它的方式:
myObject.PrintGraph();
它将递归地一直向下遍历你的图形,直到它找到可以转换为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
它只打印公共属性。
这是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);
}
以下是让它发挥作用所需的基础设施:
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;
}
答案 2 :(得分:2)
几年前我做了一些调试工作。它是一个递归函数,可以打印所有属性和子对象。您打印的方式取决于您。只需将您想要的代码放在print方法中即可。它不是“防弹”,但效果很好:
private static void displayObject(object myObject, bool displaySubObject, Type objectType)
{
print(objectType.FullName);
if (myObject == null)
{
print(STR_Null);
}
else
{
//check for collection
if (objectType.GetInterface("IEnumerable") != null)
{
int itemNb = 0;
foreach (object item in (IEnumerable)myObject)
{
displayObject(item, displaySubObject, item.GetType);
itemNb += 1;
}
}
else
{
ArrayList al = new ArrayList();
Reflection.PropertyInfo pi = default(Reflection.PropertyInfo);
Reflection.MemberInfo[] members = objectType.GetMembers();
foreach (Reflection.MemberInfo mi in objectType.GetMembers())
{
if ((mi.MemberType & Reflection.MemberTypes.Constructor) != 0){//ignore constructor}
else if (object.ReferenceEquals(mi.DeclaringType, typeof(object))) {//ignore inherited}
else if (!al.Contains(mi.Name) & (mi.MemberType & Reflection.MemberTypes.Property) != 0)
{
al.Add(mi.Name);
pi = (Reflection.PropertyInfo)mi;
if (!(displaySubObject) || (pi.PropertyType.IsValueType || pi.PropertyType.Equals(typeof(string))))
{
print(pi, myObject);
}
else
{
//display sub objects
displayObject(pi.GetValue(myObject, null), displaySubObject, i.PropertyType);
}
}
}
}
}
}
希望有所帮助