Reflection - Iterate object's properties recursively within my own assemblies (Vb.Net/3.5)

喜你入骨 提交于 2019-12-31 05:23:06

问题


I wonder if anyone can help me - I've not done much with reflection but understand the basic principles.

What I'm trying to do:

I'm in the process of developing a class that gathers a lot of information about the local system, network, etc... to be used for automated bug reporting. Instead of having to change my test harness every time I add a new property, I'd (ideally) like to be able to serialise the lot as an XML string and just display that in a textbox.

Unfortunately, the Framework won't use the default XML serializer on read-only properties (which almost all of mine are) as they wouldn't deserialize properly

[Not sure I agree with the assumption that anything serialized must be de-serializable - MS says this is a feature "by design" which I suppose I can understand - Perhaps a tag to indicate that it should be serialized anyway would be advantageous?]

The initial approach was to make properties gettable and settable (with a throw exception on the setter) but the amount of work tidying this up afterwards seems a little excessive and I would want the properties to be read-only in the final version.

What I need help with:

My current plan is to use reflection to recursively iterate through each (public) property of my topmost gathering class. The problem is, the samples I've seen don't handle things recursively. Additionally, I only want to inspect an object's properties if it's in one of my assemblies - Otherwise just call .ToString on it.

If I don't have the inspection limited to my assembly, I assume I'll get (say) a string which then contains a Length which in turn will have .Tostring method...

For the purposes of this project, I can almost guarantee no circular references within my code and as this will only be used as a development tool so I'm not too concerned about it running amok now and then.

I'd appreciate some examples/advice.

Many thanks in advance.


回答1:


This will hopefully get you started. It prints a tree directly to the console so you'll need to adjust to output XML. Then change the IsMyOwnType method to filter out the assemblies you're interested in, right now it only cares about types in the same assembly as itself.

Shared Sub RecurseProperties(o As Object, level As Integer)
    For Each pi As PropertyInfo In o.GetType().GetProperties()
        If pi.GetIndexParameters().Length > 0 Then Continue For

        Console.Write(New String(" "c, 2 * level))
        Console.Write(pi.Name)
        Console.Write(" = ")

        Dim propValue As Object = pi.GetValue(o, Nothing)
        If propValue Is Nothing Then
            Console.WriteLine("<null>")
        Else
            If IsMyOwnType(pi.PropertyType) Then
                Console.WriteLine("<object>")
                RecurseProperties(propValue, level+1)
            Else
                Console.WriteLine(propValue.ToString())
            End If
        End If

    Next
End Sub

Shared Function IsMyOwnType(t As Type) As Boolean
    Return t.Assembly Is Assembly.GetExecutingAssembly()
End Function



回答2:


you extension version on c# to use on any object

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Extensions
{
    public static class ObjectExtension
    {
        public static string ToStringProperties(this object o)
        {
            return o.ToStringProperties(0);
        }
    public static string ToStringProperties(this object o, int level)
    {
        StringBuilder sb = new StringBuilder();
        string spacer = new String(' ', 2 * level);
        if (level == 0) sb.Append(o.ToString());
        sb.Append(spacer);
        sb.Append("{\r\n");
        foreach (PropertyInfo pi in o.GetType().GetProperties())
        {

            if (pi.GetIndexParameters().Length == 0)
            {
                sb.Append(spacer);
                sb.Append("  ");
                sb.Append(pi.Name);
                sb.Append(" = ");

                object propValue = pi.GetValue(o, null);
                if (propValue == null)
                {
                    sb.Append(" <null>");
                } else {
                    if (IsMyOwnType(pi.PropertyType))
                    {
                        sb.Append("\r\n");
                        sb.Append(((object)propValue).ToStringProperties(level + 1));
                    } else{
                        sb.Append(propValue.ToString());
                    }
                }
                sb.Append("\r\n");
            }
        }
        sb.Append(spacer);
        sb.Append("}\r\n");
        return sb.ToString();
    }
    private static bool IsMyOwnType(Type t) 
{
    return (t.Assembly == Assembly.GetExecutingAssembly());
}
}
}


来源:https://stackoverflow.com/questions/1410807/reflection-iterate-objects-properties-recursively-within-my-own-assemblies-v

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!