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