Pregunta

Estoy utilizando las clases de reflexión con el fin de obtener todos los campos dentro de un determinado objeto. Mi problema sin embargo es que funciona perfectamente cuando los campos están dentro de una clase normal, como:

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.

Tengo 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 lo ejecuto, no consigo los campos de la espalda GetType().GetFields(BindingFlag.Default).

Cada uno de estos campos también tienen una propiedad, get; set; se le atribuye. Cuando ejecuto el código, consigo las propiedades de todo el camino de vuelta a test1 pero no 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);

I utilizar el mismo código para las propiedades de:

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

foreach (PropertyInfo property in properties)

Cualquier idea por qué me dan las propiedades de las clases abstractas, pero no los campos?

¿Fue útil?

Solución

Editar: Para llegar privado miembros del tipo de base, tiene que:

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

Editar de nuevo:. Win

Editar 3/22/13: Se utiliza en lugar de Concat Union. Dado que estamos especificando BindingFlags.DeclaredOnly y BaseType de un tipo que no puede ser igual a sí mismo, no es necesario Union y es más caro.

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

Otros consejos

Un tipo que hereda otro tipo no puede ver las partes íntimas de ese otro tipo, se puede ver protegida, las partes 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 la siguiente:

B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString

Por lo tanto, el tipo A tiene dos campos; PrivateString y ProtectedString. Tipo B tiene uno; ProtectedString, que hereda de A. Si se desea se puede "llegar" a través de la PrivateString B tipo, tendrá que desplazarse a su tipo base (b.GetType().BaseType).

Nota sin embargo, que aunque los informes de tipo B que tienen un campo llamado ProtectedString, este campo todavía no está declarada en B; se declara en A. Esto puede ser examinado por la adición de 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 test2 tipo (la similitud de los nombres de campo y nombres de tipos hacen esa frase un tanto confuso, yo soy miedo) .a

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 comprobado, YMMV)

Las propiedades se heredan, los campos no son. campos protegidos son visibles para descendiente clases, pero no heredada por ellos. En otras palabras, la clase descendiente en realidad tiene las propiedades de su clase base, pero es sólo capaz de ver los campos.

Si lo que desea es los nombres de ambas 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));
}

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

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top