Мне больше нравится мой, так как он компилируется. Я реализовал это как серию методов расширения и статических вещей, поэтому поместите это в статический класс где-нибудь в вашем проекте, и методы расширения будут немедленно доступны, как только вы включите пространство имен, содержащее статический класс. Вот как вы это используете:
myObject.PrintGraph();
Он будет рекурсивно туннелировать все время вниз по вашему графику, пока не найдет что-то, что он может Convert.ToString (), который затем будет отладить. Отпечатать в ваше непосредственное окно. Вот пример вывода:
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;
}