C# – GetProperties() to return all properties for an interface inheritance hierarchy

.netc++reflection

Assuming the following hypothetical inheritance hierarchy:

public interface IA
{
  int ID { get; set; }
}

public interface IB : IA
{
  string Name { get; set; }
}

Using reflection and making the following call:

typeof(IB).GetProperties(BindingFlags.Public | BindingFlags.Instance) 

will only yield the properties of interface IB, which is "Name".

If we were to do a similar test on the following code,

public abstract class A
{
  public int ID { get; set; }
}

public class B : A
{
  public string Name { get; set; }
}

the call typeof(B).GetProperties(BindingFlags.Public | BindingFlags.Instance) will return an array of PropertyInfo objects for "ID" and "Name".

Is there an easy way to find all the properties in the inheritance hierarchy for interfaces as in the first example?

Best Solution

I've tweaked @Marc Gravel's example code into a useful extension method encapsulates both classes and interfaces. It also add's the interface properties first which I believe is the expected behaviour.

public static PropertyInfo[] GetPublicProperties(this Type type)
{
    if (type.IsInterface)
    {
        var propertyInfos = new List<PropertyInfo>();

        var considered = new List<Type>();
        var queue = new Queue<Type>();
        considered.Add(type);
        queue.Enqueue(type);
        while (queue.Count > 0)
        {
            var subType = queue.Dequeue();
            foreach (var subInterface in subType.GetInterfaces())
            {
                if (considered.Contains(subInterface)) continue;

                considered.Add(subInterface);
                queue.Enqueue(subInterface);
            }

            var typeProperties = subType.GetProperties(
                BindingFlags.FlattenHierarchy 
                | BindingFlags.Public 
                | BindingFlags.Instance);

            var newPropertyInfos = typeProperties
                .Where(x => !propertyInfos.Contains(x));

            propertyInfos.InsertRange(0, newPropertyInfos);
        }

        return propertyInfos.ToArray();
    }

    return type.GetProperties(BindingFlags.FlattenHierarchy
        | BindingFlags.Public | BindingFlags.Instance);
}