2009-07-20 1 views
22

Я использую классы Reflection, чтобы получить все поля внутри определенного объекта. Моя проблема, однако, является то, что она прекрасно работает, когда поля внутри обычный класс, как:Не получать поля из GetType(). GetFields with BindingFlag.Default

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) 

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

ответ

44

Edit: Для того, чтобы получить частные члены базового типа, вы должны:

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

Редактировать снова: Win.

Редактировать 3/22/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)); 
} 
+0

В любом случае не будет иметь большого значения, так как поля не являются статическими. –

+0

Я пробовал: FieldInfo [] fields = Obj.GetType(). GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); Но он все еще не работает. – Patrick

+0

Ну, я попробовал: FieldInfo [] fields = Obj.GetType(). GetFields (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy); Но все равно не повезло. – Patrick

2

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

+0

Объекты, созданные из производного типа * do *, содержат в нем поля экземпляра базового типа. –

+0

Итак, нет способа получить GetType() для получения полей? – Patrick

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. Если вы хотите «дотянуться» до PrivateString по типу B, вам нужно будет перейти к его базовому типу (b.GetType().BaseType).

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

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

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)

+1

Вы должны включить 'флаги | = BindingFlags.DeclaredOnly' в реализации или вы Будут дубликаты. –

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 bindingFlags) => 
     type.BaseType?.EnumerateFields(bindingFlags) 
      .Concat(type.GetFields(bindingFlags | BindingFlags.DeclaredOnly)) ?? 
     type.EnumerateFields(bindingFlags); 
+0

Пожалуйста, старайтесь избегать просто сдачи кода в качестве ответа и попытайтесь объяснить, что он делает и почему. Ваш код может быть не очевидным для людей, у которых нет соответствующего опыта в кодировании. Измените свой ответ, чтобы включить [пояснение, контекст и попытаться упомянуть любые ограничения, допущения или упрощения в вашем ответе.] (Https://stackoverflow.com/help/how-to-answer) –

+0

Спасибо, описание было добавлено. – Makeman

Смежные вопросы