简体   繁体   中英

How do you get the all properties of a class and its base classes (up the hierarchy) with Reflection? (C#)

So what I have right now is something like this:

PropertyInfo[] info = obj.GetType().GetProperties(BindingFlags.Public);

where obj is some object.

The problem is some of the properties I want aren't in obj.GetType() they're in one of the base classes further up. If I stop the debugger and look at obj, the I have to dig through a few "base" entries to see the properties I want to get at. Is there some binding flag I can set to have it return those or do I have to recursively dig through the Type.BaseType hierarchy and do GetProperties on all of them?

Use this:

PropertyInfo[] info = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

EDIT: Of course the correct answer is that of Jay . GetProperties() without parameters is equivalent to GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static ) . The BindingFlags.FlattenHierarchy plays no role here.

I don't think it's that complicated.

If you remove the BindingFlags parameter to GetProperties, I think you get the results you're looking for:

    class B
    {
        public int MyProperty { get; set; }
    }

    class C : B
    {
        public string MyProperty2 { get; set; }
    }

    static void Main(string[] args)
    {
        PropertyInfo[] info = new C().GetType().GetProperties();
        foreach (var pi in info)
        {
            Console.WriteLine(pi.Name);
        }
    }

produces

MyProperty2
    MyProperty

If you access Type.BaseType , you can get the base type. You can recursively access each base type and you'll know when you've hit the bottom when your type is System.Object .

Type type = obj.GetType();
PropertyInfo[] info = type.GetProperties(BindingFlags.Public);
PropertyInfo[] baseProps = type.BaseType.GetProperties(BindingFlags.Public);

I would tend to agree with Nicolas; unless you know you need reflection, then ComponentModel is a viable alternative, with the advantage that you will get the correct metadata even for runtime models (such as DataView / DataRowView ).

For example:

    foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
    {
        Console.WriteLine("{0}={1}", prop.Name, prop.GetValue(obj));
    }

As an aside, you can also do some simple performance tricks with this; you can do the same with reflection and Delegate.CreateDelegate , but there is no centralised place to hide the logic away, unlike TypeDescriptor with a TypeDescriptionProvider (don't worry if these are unfamiliar; you can just use the code "as is" ;-p).

利用:

TypeDescriptor.GetProperties(obj);

Just to be complete, you can't get PRIVATE fields and properties from base classes this way. You'll have to use a recursive loop for that:

public static IEnumerable<PropertyInfo> GetProperties(Type type, bool forGetter)
{
    // Loop over public and protected members
    foreach (var item in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
    {
        yield return item;
    }

    // Get first base type
    type = type.BaseType;

    // Find their "private" memebers
    while (type != null && type != typeof(object))
    {
        // Loop over non-public members
        foreach (var item in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic))
        {
            // Make sure it's private!
            // To prevent doubleing up on protected members
            var methodInfo = forGetter ? item.GetGetMethod(true) : item.GetSetMethod(true);
            if (methodInfo != null && methodInfo.IsPrivate)
            {
                yield return item;
            }
        }

        // Get next base type.
        type = type.BaseType;
    }
}

and

public static IEnumerable<FieldInfo> GetFields(Type type)
{
    // Loop over public and protected members
    foreach (var item in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
    {
        yield return item;
    }

    // Get first base type
    type = type.BaseType;

    // Find their "private" memebers
    while (type != null && type != typeof(object))
    {
        // Loop over non-public members
        foreach (var item in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
        {
            // Make sure it's private!
            // To prevent doubleing up on protected members
            if (item.IsPrivate)
            {
                yield return item;
            }
        }

        // Get next base type.
        type = type.BaseType;
    }
}

Note: you will get PROTECTED fields & properties twice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM