2009-07-20 14 views
22

Estoy usando las clases Reflection para obtener todos los campos dentro de un objeto determinado. Mi problema sin embargo es que funciona perfectamente cuando los campos están dentro de una clase normal, como:No obteniendo campos de GetType(). GetFields con BindingFlag.Default

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

Aquí tengo tanto test1 y test2, mi problema es que yo uso la abstracción y por lo tanto varias clases combinadas.

que tiene algo como:

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

Pero cuando corro, yo no obtienen los campos detrás de la GetType().GetFields(BindingFlag.Default).

Todos los campos también tienen una propiedad, get; set; adjunta. Cuando ejecuto el código, devuelvo las propiedades a test1 pero no a los campos reales.

Este es el código que estoy tratando de conseguir los campos con:

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

También he intentado:

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

Puedo utilizar el mismo código para las propiedades:

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

foreach (PropertyInfo property in properties) 

¿Alguna idea de por qué obtengo las propiedades de las clases abstractas pero no de los campos?

Respuesta

44

Editar: Para llegar miembros privados del tipo base, tiene que:

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

de nuevo Edit: Win.

Editar 3/22/13: Usado Concat en lugar de Union. Dado que estamos especificando BindingFlags.DeclaredOnly y un tipo de BaseType no se puede igualar a sí mismo, Union no es necesario y es más costoso.

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

No supondría una gran diferencia, ya que los campos no son estáticos. –

+0

Intenté: FieldInfo [] fields = Obj.GetType(). GetFields (BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); Pero aún así no funciona. – Patrick

+0

Bueno, probé: FieldInfo [] fields = Obj.GetType(). GetFields (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy); Pero todavía no hay suerte. – Patrick

2

Las propiedades se heredan, los campos no. Los campos protegidos son visibles para las clases descendientes, pero no heredados por ellos. En otras palabras, la clase descendiente en realidad tiene las propiedades de su clase base, pero solo puede ver los campos.

+0

Los objetos creados de un tipo derivado * do * tienen los campos de instancia del tipo de base incluidos en él. –

+0

¿Entonces no hay forma de que getType() obtenga los campos? – Patrick

4

Un tipo que hereda otro tipo no puede ver partes privadas de ese otro tipo, puede ver partes protegidas, internas y públicas. Considere el siguiente código:

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

    } 
} 

La salida de este programa es el siguiente:

B Fields: 
ProtectedString 
A Fields: 
PrivateString 
ProtectedString 

Por lo tanto, el tipo A tiene dos campos; PrivateString y ProtectedString. El tipo B tiene uno; ProtectedString, que hereda de A. Si desea "llegar" al PrivateString a través del tipo B, deberá navegar a su tipo base (b.GetType().BaseType).

Sin embargo, tenga en cuenta que incluso si el tipo B informa tener un campo llamado ProtectedString, este campo aún no se declara en B; está declarado en A. Esto se puede examinar agregando BindingFlags.DeclaredOnly a las llamadas GetFields en el programa de ejemplo anterior; GetFields no devolverá campos para B, y dos para A.

Traducido a su ejemplo de código, esto significa que el tipo test3 no contiene los campos test2 y test3, ya que son privados para el tipo test2 (la similitud de los nombres de campo y nombres de tipos hacen esa frase un tanto confuso, yo temo) .a

3

puede utilizar este método de extensión para recorrer de forma recursiva jerarquía de herencia de un tipo hasta el final hasta que objetar, volviendo de manera efectiva todos los campos del tipo y de todos sus antepasados:

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

(no probado , YMMV)

+1

Debe incluir 'banderas | = BindingFlags.DeclaredOnly' en la ejecución o Obtendré duplicados. –

0

Si sólo desea que los nombres de las propiedades y campos, utilice

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

Enumeración de todos los campos de tipo incluyendo los miembros privados de clases base.

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags bindingFlags) => 
     type.BaseType?.EnumerateFields(bindingFlags) 
      .Concat(type.GetFields(bindingFlags | BindingFlags.DeclaredOnly)) ?? 
     type.EnumerateFields(bindingFlags); 
+0

Por favor, trate de evitar solo el código de dumping como una respuesta y trate de explicar lo que hace y por qué. Es posible que su código no sea obvio para las personas que no tienen la experiencia de codificación relevante. Edite su respuesta para incluir [aclaraciones, contexto y trate de mencionar cualquier limitación, suposición o simplificación en su respuesta.] (Https://stackoverflow.com/help/how-to-answer) –

+0

Gracias, se agregó la descripción. – Makeman

Cuestiones relacionadas