c# - 列出对象属性,例如 Visual Studio 立即窗口

标签 c# reflection

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

最佳答案

你可以尝试这样的事情:

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

关于c# - 列出对象属性,例如 Visual Studio 立即窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4504249/

相关文章:

Scala:获取内部类型的 TypeTag

java - 字段存在时出现 NoSuchFieldException

java - 通过反射运行 jetty Web 服务

c# - C# 中的反射——想要一个类字段的数据类型列表

Java:instanceof vs 类名切换性能

c# - 授权集成到客户端-服务器应用程序(C#、JavaScript)

c# - 使用 Unity3D API 了解陀螺仪读数

c# - 对象与集合的 Entity Framework 更新方法

c# - 如何从进程中获取输出?

c# - 从通用存储库派生的类