Вопрос по reflection, bindingflags, c# – Не получать поля из GetType (). GetFields с BindingFlag.Default

24

Я использую классы Reflection для того, чтобы получить все поля внутри определенного объекта. Моя проблема, однако, заключается в том, что он отлично работает, когда поля находятся внутри нормального класса, например:

class test
{
   string test1 = string.Empty;
   string test2 = string.Empty;
}

Здесь я получаю как test1, так и test2, моя проблема в том, что я использую абстракцию и, следовательно, несколько классов вместе.

Я получил что-то вроде:

class test3 : test2
{
   string test4 = string.Empty;
   string test5 = string.Empty;
}

class test2 : test1
{
   string test2 = string.Empty;
   string test3 = string.Empty;
}
class test1
{
   string test0 = string.Empty;
   string test1 = string.Empty;
}

Но когда я запускаю его, я не получаю поля отGetType().GetFields(BindingFlag.Default).

Каждый из этих полей также имеет свойство,get; set; прикреплен к нему. Когда я запускаю код, я получаю свойства вплоть до test1, но не фактические поля.

Это код, который я пытаюсь получить с помощью полей:

FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Default);
foreach (FieldInfo field in fields)

Я также попробовал:

FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Public 
                                             | BindingFlags.Instance 
                                             | BindingFlags.NonPublic 
                                             | BindingFlags.Static);

Я использую тот же код для свойств:

PropertyInfo[] properties = Obj.GetType().GetProperties(BindingFlags.Public 
                                             | BindingFlags.Instance 
                                             | BindingFlags.NonPublic 
                                             | BindingFlags.Static);

foreach (PropertyInfo property in properties)

Любые идеи, почему я получаю свойства из абстрагированных классов, но не полей?

Ваш Ответ

6   ответов
4

Тип, который наследует другой тип, не может видеть закрытые части этого другого типа, он может видеть защищенную, внутреннюю и открытую части. Рассмотрим следующий код:

class A
{
    // note that this field is private
    string PrivateString = string.Empty;
    // protected field
    protected string ProtectedString = string.Empty;
}

class B : A { }

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("B Fields:");
        B b = new B();
        b.GetType()
            .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
            .ToList()
            .ForEach(f => Console.WriteLine(f.Name));

        Console.WriteLine("A Fields:");
        A a = new A();
        a.GetType()
            .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
            .ToList()
            .ForEach(f => Console.WriteLine(f.Name));

    }
}

Вывод этой программы следующий:

B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString

Итак, типA имеет два поля;PrivateString а такжеProtectedString, ТипB имеет один;ProtectedStringчто он наследует отA, Если вы хотите & quot; достичь & quot;PrivateString через типB, вам нужно будет перейти к его базовому типу (b.GetType().BaseType).

Обратите внимание, что даже если типB сообщает, чтобы иметь поле под названиемProtectedStringэто поле еще не объявлено вB; объявлено вA, Это можно проверить, добавивBindingFlags.DeclaredOnly кGetFields звонки в приведенном выше примере программы;GetFields не вернет поля дляBи два дляA.

В переводе на ваш пример кода это означает, что типtest3 не содержит полейtest2 а такжеtest3, поскольку они являются частными для типаtest2 (боюсь, сходство имен полей и имен типов делает это предложение несколько запутанным) .a

2

Свойства наследуются, поля нет. Защищенные поля видимы для классов-потомков, но не наследуются ими. Другими словами, класс-потомок на самом деле имеет свойства своего базового класса, но он просто способен видеть поля.

Объекты, созданные из производного типаdo иметь включенные в него поля экземпляра базового типа.
То есть у GetType () нет способа получить поля? Patrick
47

Изменить: чтобы получитьprivate Для членов базового типа необходимо:

typeof(T).BaseType.GetFields(...)

Отредактируйте снова: Win.

Редактировать 22.03.13: ИспользуетсяConcat вместоUnion, Поскольку мы указываемBindingFlags.DeclaredOnly и типBaseType не может сравниться,Union не нужен и стоит дороже.

public static IEnumerable<FieldInfo> GetAllFields(Type t)
{
    if (t == null)
        return Enumerable.Empty<FieldInfo>();

    BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | 
                         BindingFlags.Static | BindingFlags.Instance | 
                         BindingFlags.DeclaredOnly;
    return t.GetFields(flags).Concat(GetAllFields(t.BaseType));
}
Я пытался: FieldInfo [] fields = Obj.GetType (). GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); Но это все еще не работает. Patrick
Ну, я попробовал: FieldInfo [] fields = Obj.GetType (). GetFields (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy); Но все равно не повезло. Patrick
В любом случае это не будет иметь большого значения, поскольку поля не являются статичными.
Ну, я попробовал это: (все еще не повезло с этим) FieldInfo [] fields = Obj.GetType (). BaseType.GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); Obj - это объект, переданный из вызывающего класса, так как я не знаю, какой класс вызывает функцию, я использовал для нее объект. void Check (объект Obj) Patrick
@ Патрик: Теперь я получил и проверил это :)
0

Если вы просто хотите имена как для свойств, так и для полей, используйте

private static IEnumerable<string > GetAllFieldsAndProperties(Type t)
{
  if (t == null)
    return Enumerable.Empty<string>();

  BindingFlags flags = BindingFlags.Public 
    | BindingFlags.NonPublic 
    | BindingFlags.Static 
    | BindingFlags.Instance 
    | BindingFlags.DeclaredOnly;
  return t.GetFields(flags).Select(x=>x.Name)
    .Union(GetAllFieldsAndProperties(t.BaseType))
    .Union(t.GetProperties(flags).Select(x=>x.Name));
}
0

Перечисление всех типов полей, включая закрытые члены базовых классов.

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
Спасибо, описание было добавлено.
Пожалуйста, постарайтесь не просто выводить код в качестве ответа и попытаться объяснить, что он делает и почему. Ваш код может быть неочевиден для людей, которые не имеют соответствующего опыта кодирования. Пожалуйста, отредактируйте ваш ответ, чтобы включитьclarification, context and try to mention any limitations, assumptions or simplifications in your answer.
3

Вы можете использовать этот метод расширения для рекурсивного обхода иерархии наследования типа вплоть до объекта, эффективно возвращая все поля типа и всех его предков:

public static class ReflectionExtensions
{
    public static IList<FieldInfo> GetAllFields(this Type type, BindingFlags flags)
    {
        if(type == typeof(Object)) return new List<FieldInfo>();

        var list = type.BaseType.GetAllFields(flags);
        // in order to avoid duplicates, force BindingFlags.DeclaredOnly
        list.AddRange(type.GetFields(flags | BindingFlags.DeclaredOnly));
        return list;
    }
}

(Не проверено, YMMV)

Вы должны включитьflags |= BindingFlags.DeclaredOnly в реализации, или вы получите дубликаты.

Похожие вопросы