29

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?

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Davy8
  • 30,868
  • 25
  • 115
  • 173

6 Answers6

29

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.

Community
  • 1
  • 1
Panos
  • 18,992
  • 6
  • 45
  • 54
  • I'm marking this as the answer because although Jay's works and would get me what I want, this explains why it works. I just assumed that if neither Instance nor Static were specified it would default to both, when in fact it was returning neither. – Davy8 Oct 28 '08 at 23:47
  • There were no top level properties in the object I was looking at, so I assumed that it was just trying to retrieve the top level ones when it returned nothing, when in fact it returned nothing because it was trying to get properties that were neither Static nor Instance. – Davy8 Oct 28 '08 at 23:48
  • 2
    I have a base class with some nonPublic field, when i call .GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) on that it return non public field, when i do on the child , it return only public fields /child fields, (child only contains public field, and parent contains fields which sets by system, so it's private) – Hassan Faghihi Sep 16 '19 at 07:52
  • 1
    As per @HassanFaghihi's comment - this answer is incorrect, it only *coincidentally* works for *public* base-type / grand-base-type properties. – Adam Apr 22 '22 at 17:06
  • @Adam probably the answer is incorrect - it is a 14-year old answer... But it does not work coincidentally - it works exactly as the OP wanted. Hassan asked a different question so he should get a different answer... – Panos Apr 25 '22 at 05:59
  • @Panos at 14 years ago, we were using the .Net framework and no .Net standard or .Net core or .Net (alone) were there, so the sub-structure and behavior may differ from that time, or at least in other sub-systems. even the .Net Framework era itself splits into two parts of after .Net Framework 4 and before .Net Framework 4, and 2008 I believe there was .Net Framework 3.5... But no matter what still most of the code and behavior are identical – Hassan Faghihi Apr 27 '22 at 06:20
17

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
Jay Bazuzi
  • 45,157
  • 15
  • 111
  • 168
8

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);
Seibar
  • 68,705
  • 38
  • 88
  • 99
3

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

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
2

Use:

TypeDescriptor.GetProperties(obj);
Nicolas Cadilhac
  • 4,680
  • 5
  • 41
  • 62
0

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.

Luc Bloom
  • 1,120
  • 12
  • 18