Declaring a property in a derived class that matches the name of a property in the base class \"hides\" it (unless it overrides it with the override
keyword).
GetProperties is defined as all public properties of the type.
You could get their get and set methods using:
typeof(C).GetMethods()
.Where(m => m.Name.StartsWith("set_") || m.Name.StartsWith("get_"))
Although this seems like a bad idea, compared to going down the inheritance hierarchy to get the properties.
I do not think it is possible without traversing the inheritance hierarchy. It does not have to be too much code, though:
public static IEnumerable<PropertyInfo> GetAllProperties(Type t)
{
while (t != typeof(object))
{
foreach (var prop in t.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance))
yield return prop;
t = t.BaseType;
}
}
Of course, if you know a common basetype you can stop at, instead of object, it will be more efficient. Also; it will take some time to do the reflection, so cache the result. After all, the type information won't change during execution.
Through reflection, the new keyword only hides the inherited property if the signature matches. I guess reflection matches signatures on property accessors (get_ & set_). It's the reasons why GetProperties()
returns B.P and C.P when the return type differ.
I recently discovered Fasteflect which provides advanced reflection mechanisms.
I checked and Fasteflect type.Properties
returns all the tree of hidden members (P). I think the API consider backing members (virtual/override) and hidden members (new) differently which is a good thing for your 'problem' ;)
My test with fasterflect :
class Class1
{
public object field1 = null;
public virtual object Property1 { get; set; }
public object Property2 { get; set; }
public string Property3 { get; set; }
}
class Class2 : Class1
{
public new object field1 = null;
public override object Property1 { get; set; }
public new string Property3 { get; set; }
}
class Class3 : Class2
{
public new string Property3 { get; set; }
}
Filter backing members but returns all hidden members :
typeof(Class3).Properties(Flags.ExcludeBackingMembers | Flags.Public | Flags.Instance)
[0] {System.String Property3} System.Reflection.PropertyInfo
[1] {System.Object Property1} System.Reflection.PropertyInfo
[2] {System.String Property3} System.Reflection.PropertyInfo
[3] {System.Object Property2} System.Reflection.PropertyInfo
[4] {System.String Property3} System.Reflection.PropertyInfo