Вывод списка свойств объекта, таких как окно Visual Studio Immediate - PullRequest
2 голосов
/ 22 декабря 2010

Я храню несколько занятий в сессии.Я хочу иметь возможность видеть значения свойств моего класса в средстве просмотра трассировки.По умолчанию у меня только имя типа MyNamespace.MyClass.Мне было интересно, если я перезаписываю метод .ToString () и использую отражение, чтобы перебрать все свойства и создать такую ​​строку ... это бы сработало, но просто хотелось посмотреть, есть лиуже там (особенно, поскольку Immediate Window имеет такую ​​возможность) , которая делает то же самое ... т.е. выводит значения свойства класса в трассировке, а не только имя класса.

Ответы [ 3 ]

3 голосов
/ 22 декабря 2010

Вы можете попробовать что-то подобное:

static void Dump(object o, TextWriter output)
{
    if (o == null)
    {
        output.WriteLine("null");
        return;
    }

    var properties =
        from prop in o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
        where prop.CanRead
        && !prop.GetIndexParameters().Any() // exclude indexed properties to keep things simple
        select new
        {
            prop.Name,
            Value = prop.GetValue(o, null)
        };

    output.WriteLine(o.ToString());
    foreach (var prop in properties)
    {
        output.WriteLine(
            "\t{0}: {1}",
            prop.Name,
            (prop.Value ?? "null").ToString());
    }
}

Конечно, это не очень эффективно из-за отражения ... Лучшим решением было бы динамически генерировать и кэшировать метод dumper для каждого конкретного типа.


РЕДАКТИРОВАТЬ: вот улучшенное решение, которое использует выражения Linq для генерации специализированного метода дампера для каждого типа. Чуть сложнее;)

static class Dumper
{
    private readonly static Dictionary<Type, Action<object, TextWriter>> _dumpActions
        = new Dictionary<Type, Action<object, TextWriter>>();

    private static Action<object, TextWriter> CreateDumper(Type type)
    {
        MethodInfo writeLine1Obj = typeof(TextWriter).GetMethod("WriteLine", new[] { typeof(object) });
        MethodInfo writeLine1String2Obj = typeof(TextWriter).GetMethod("WriteLine", new[] { typeof(string), typeof(object), typeof(object) });

        ParameterExpression objParam = Expression.Parameter(typeof(object), "o");
        ParameterExpression outputParam = Expression.Parameter(typeof(TextWriter), "output");
        ParameterExpression objVariable = Expression.Variable(type, "o2");
        LabelTarget returnTarget = Expression.Label();
        List<Expression> bodyExpressions = new List<Expression>();

        bodyExpressions.Add(
            // o2 = (<type>)o
            Expression.Assign(objVariable, Expression.Convert(objParam, type)));

        bodyExpressions.Add(
            // output.WriteLine(o)
            Expression.Call(outputParam, writeLine1Obj, objParam));

        var properties =
            from prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
            where prop.CanRead
            && !prop.GetIndexParameters().Any() // exclude indexed properties to keep things simple
            select prop;

        foreach (var prop in properties)
        {
            bool isNullable =
                !prop.PropertyType.IsValueType ||
                prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>);

            // (object)o2.<property> (cast to object to be passed to WriteLine)
            Expression propValue =
                 Expression.Convert(
                     Expression.Property(objVariable, prop),
                     typeof(object));

            if (isNullable)
            {
                // (<propertyValue> ?? "null")
                propValue =
                    Expression.Coalesce(
                        propValue,
                        Expression.Constant("null", typeof(object)));
            }

            bodyExpressions.Add(
                // output.WriteLine("\t{0}: {1}", "<propertyName>", <propertyValue>)
                Expression.Call(
                    outputParam,
                    writeLine1String2Obj,
                    Expression.Constant("\t{0}: {1}", typeof(string)),
                    Expression.Constant(prop.Name, typeof(string)),
                    propValue));
        }

        bodyExpressions.Add(Expression.Label(returnTarget));

        Expression<Action<object, TextWriter>> dumperExpr =
            Expression.Lambda<Action<object, TextWriter>>(
                Expression.Block(new[] { objVariable }, bodyExpressions),
                objParam,
                outputParam);

        return dumperExpr.Compile();
    }

    public static void Dump(object o, TextWriter output)
    {
        if (o == null)
        {
            output.WriteLine("null");
        }

        Type type = o.GetType();
        Action<object, TextWriter> dumpAction;
        if (!_dumpActions.TryGetValue(type, out dumpAction))
        {
            dumpAction = CreateDumper(type);
            _dumpActions[type] = dumpAction;
        }
        dumpAction(o, output);
    }
}

Использование:

Dumper.Dump(myObject, Console.Out);
3 голосов
/ 22 декабря 2010

Я считаю, что это было бы полезно: C # объект dumper

1 голос
/ 25 марта 2013

Это код, который я использую.Я нахожу это невероятно полезным и почти мгновенно.Код использует конвертер JSON Newtonsoft.

    [System.Obsolete("ObjectDump should not be included in production code.")]
    public static void Dump(this object value)
    {
        try
        {
            System.Diagnostics.Trace.WriteLine(JsonConvert.SerializeObject(value, Formatting.Indented));
        }
        catch (Exception exception)
        {
            System.Diagnostics.Trace.WriteLine("Object could not be formatted. Does it include any interfaces? Exception Message: " + exception.Message);
        }
    }

Добавьте это в общую библиотеку, сделайте ссылку на нее и добавьте ее в предложение using.Можно использовать в непосредственном окне, введя YourObject.Dump () (точно так же, как в linqpad).

Классы, включая интерфейсы, должны обрабатываться по-разному, поскольку это просто конвертер JSON.Обходной путь для классов, которые включают реализации интерфейса, которые я использую, состоит в том, чтобы удалить пустой конструктор по умолчанию и реализовать конструктор, используя конкретные экземпляры интерфейсов.

Я считаю JSON очень простым форматом для чтения и рассматриваю этот небольшой методнеоценим для отладки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...