Не получать поля из GetType (). GetFields с BindingFlag.Default

Я использую классы 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)

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

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)

 20 июл. 2009 г., 22:13
Вы должны включитьflags |= BindingFlags.DeclaredOnly в реализации, или вы получите дубликаты.
Решение Вопроса

Изменить: чтобы получить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));
}
 20 июл. 2009 г., 21:49
В любом случае это не будет иметь большого значения, поскольку поля не являются статичными.
 Patrick20 июл. 2009 г., 21:54
Ну, я попробовал: FieldInfo [] fields = Obj.GetType (). GetFields (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy); Но все равно не повезло.
 20 июл. 2009 г., 22:02
@ Патрик: Теперь я получил и проверил это :)
 Patrick20 июл. 2009 г., 22:06
Ну, я попробовал это: (все еще не повезло с этим) FieldInfo [] fields = Obj.GetType (). BaseType.GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); Obj - это объект, переданный из вызывающего класса, так как я не знаю, какой класс вызывает функцию, я использовал для нее объект. void Check (объект Obj)
 Patrick20 июл. 2009 г., 21:50
Я пытался: FieldInfo [] fields = Obj.GetType (). GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); Но это все еще не работает.

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

 20 июл. 2009 г., 21:49
Объекты, созданные из производного типаdo иметь включенные в него поля экземпляра базового типа.
 Patrick20 июл. 2009 г., 21:51
То есть у GetType () нет способа получить поля?

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

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

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

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

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

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));
}

Ваш ответ на вопрос