列出对象属性,如Visual Studio立即窗口

时间:2010-12-21 21:48:47

标签: c# reflection

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

3 个答案:

答案 0 :(得分:3)

我相信这会有所帮助:C# object dumper

答案 1 :(得分:3)

你可以尝试这样的事情:

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

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


编辑:这是一个改进的解决方案,它使用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);

答案 2 :(得分:1)

这是我使用的代码。我发现它非常有用,几乎是即时的。代码使用的是Newtonsoft JSON转换器。

    [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是一种非常简单的阅读格式,并认为这种小方法非常适合调试。