Как вы получаете все свойства класса и его базовых классов (вверх по иерархии) с помощью Reflection? (С #)
Итак, то, что у меня сейчас есть, примерно так:
PropertyInfo[] info = obj.GetType().GetProperties(BindingFlags.Public);
где obj
это какой-то объект.
Проблема в том, что некоторые свойства, которые я хочу, не находятся в obj.GetType()
они в одном из базовых классов дальше. Если я остановлю отладчик и посмотрю на obj, мне придется пролистать несколько "базовых" записей, чтобы увидеть свойства, к которым я хочу получить. Есть ли какой-нибудь флаг привязки, который я могу установить, чтобы он возвращал их, или я должен рекурсивно копаться в Type.BaseType
иерархия и сделать GetProperties
на всех из них?
6 ответов
Использовать этот:
PropertyInfo[] info = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
РЕДАКТИРОВАТЬ: Конечно, правильный ответ-это Джей. GetProperties()
без параметров эквивалентно GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static )
, BindingFlags.FlattenHierarchy
здесь не играет никакой роли.
Я не думаю, что это так сложно.
Если вы удалите BindingFlags
Параметр GetProperties, я думаю, вы получите результаты, которые вы ищете:
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);
}
}
производит
MyProperty2 Моя собственность
Если вы получаете доступ Type.BaseType
Вы можете получить базовый тип. Вы можете рекурсивно получить доступ к каждому базовому типу, и вы будете знать, когда достигните дна, когда ваш тип System.Object
,
Type type = obj.GetType();
PropertyInfo[] info = type.GetProperties(BindingFlags.Public);
PropertyInfo[] baseProps = type.BaseType.GetProperties(BindingFlags.Public);
Я хотел бы согласиться с Николасом; если вы не знаете, что вам нужно отражение, то ComponentModel
является жизнеспособной альтернативой, с преимуществом, что вы получите правильные метаданные даже для моделей времени выполнения (таких как DataView
/DataRowView
).
Например:
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
{
Console.WriteLine("{0}={1}", prop.Name, prop.GetValue(obj));
}
Кроме того, вы также можете сделать несколько простых трюков производительности с этим; вы можете сделать то же самое с отражением и Delegate.CreateDelegate
, но нет централизованного места, чтобы скрыть логику, в отличие от TypeDescriptor
с TypeDescriptionProvider
(не волнуйтесь, если они незнакомы; вы можете просто использовать код "как есть";-p).
Чтобы быть полным, вы не можете получить PRIVATE поля и свойства из базовых классов таким образом. Для этого вам придется использовать рекурсивный цикл:
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;
}
}
а также
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;
}
}
Примечание: вы дважды получите ЗАЩИЩЕННЫЕ поля и свойства.