Скрытие и отражение собственности (С#)
Объявление свойства в производном классе, которое соответствует имени свойства в базовом классе, "скрывает" его (если оно не переопределяет его с помощью ключевого слова override
). И свойства базового, и производного класса будут возвращены Type.GetProperties()
, если их типы не совпадают. Однако, если их типы совпадают, то в результате возвращается только свойство производного класса. Например:
class A
{
protected double p;
public int P { get { return (int)p; } set { p = value; } }
}
class B : A
{
public new int P { get { return (int)p; } set { p = value; } }
}
class C : B
{
public new float P { get { return (float)p; } set { p = value; } }
}
Вызов typeof(C).GetProperties()
приведет только к возврату B.P и C.P. Можно ли вызвать GetProperties()
таким образом, чтобы он возвращал все три? Существует почти наверняка способ сделать это, пройдя иерархию наследования, но есть ли более чистое решение?
Ответы
Ответ 1
GetProperties определяется как все общедоступные свойства типа.
Вы можете получить их методы получения и установки, используя:
typeof(C).GetMethods()
.Where(m => m.Name.StartsWith("set_") || m.Name.StartsWith("get_"))
Хотя это кажется плохой идеей, по сравнению с тем, чтобы спуститься по иерархии наследования, чтобы получить свойства.
Ответ 2
Я не думаю, что это возможно без пересечения иерархии наследования. Это не должно быть слишком много кода:
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;
}
}
Конечно, если вы знаете общий базовый тип, который вы можете остановить, вместо объекта, он будет более эффективным. Также; это займет некоторое время, чтобы сделать отражение, поэтому кешируйте результат. В конце концов, информация о типе не будет меняться во время выполнения.
Ответ 3
Благодаря отражению новое ключевое слово только скрывает унаследованное свойство, если подпись соответствует. Я думаю, что отражение соответствует подписям на аксессуарах свойств (get_ и set_). Это причины, по которым GetProperties()
возвращает B.P и C.P, когда тип возврата отличается.
Недавно я обнаружил Fasteflect, который обеспечивает расширенные механизмы отражения.
Я проверил и Fasteflect type.Properties
возвращает все дерево скрытых элементов (P). Я думаю, что API рассматривает возможность поддержки членов (virtual/override) и скрытых членов (новых) по-разному, что хорошо для вашей "проблемы";)
Мой тест с быстрым отражением:
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; }
}
Отфильтровать элементы фильтра, но возвращает все скрытые элементы:
typeof(Class3).Properties(Flags.ExcludeBackingMembers | Flags.Public | Flags.Instance)
- typeof (Class3).Properties(флаги .ExcludeBackingMembers | Flags.Public | Flags.Instance) Count = 5 System.Collections.Generic.IList
-
[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