列出对象属性,如 Visual Studio 立即窗口 [英] Listing object properties like the Visual Studio Immediate window

查看:39
本文介绍了列出对象属性,如 Visual Studio 立即窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在会话中存储了一些类.我希望能够在跟踪查看器中查看我的类属性的值.默认情况下,我只有类型名称 MyNamespace.MyClass.我想知道我是否覆盖了 .ToString() 方法并使用反射来遍历所有属性并构造一个这样的字符串......它可以做到这一点,但只是想看看是否有任何已经存在的(特别是因为立即窗口具有此功能),它的作用相同......即在跟踪中列出类属性值,而不仅仅是类的名称.

I store a few classes in session. I want to be able to see the values of my class properties in trace viewer. By default I only the Type name MyNamespace.MyClass. I was wondering if I overwrite the .ToString() method and use reflection to loop over all the properties and construct a string like that ... it would do the trick but just wanted to see if there is anything already out there (specially since Immediate Window has this capability) which does the same ... i.e. list the class property values in trace instead of just the Name of the class.

推荐答案

你可以试试这样的:

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());
    }
}

当然,由于反射,它的效率不是很高……更好的解决方案是为每种特定类型动态生成和缓存转储程序方法.

Of course, it's not very efficient because of the reflection... A better solution would be to dynamically generate and cache a dumper method for each specific type.

这是一个改进的解决方案,它使用 Linq 表达式为每种类型生成专门的转储程序方法.稍微复杂一点;)

here's an improved solution, that uses Linq expressions to generate a specialized dumper method for each type. Slightly more complex ;)

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);

这篇关于列出对象属性,如 Visual Studio 立即窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆