Как вы получаете все свойства класса и его базовых классов (вверх по иерархии) с помощью 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).

Использование:

TypeDescriptor.GetProperties(obj);

Чтобы быть полным, вы не можете получить 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;
    }
}

Примечание: вы дважды получите ЗАЩИЩЕННЫЕ поля и свойства.

Другие вопросы по тегам