c# - No obtener campos de GetType(). GetFields with BindingFlag.Default
reflection bindingflags (6)
Estoy usando las clases de Reflexión para obtener todos los campos dentro de un determinado objeto. Sin embargo, mi problema 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í obtengo tanto test1 como test2, mi problema es que 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 GetType().GetFields(BindingFlag.Default)
los campos del GetType().GetFields(BindingFlag.Default)
.
Cada uno de esos campos también tiene una propiedad, get; set;
get; set;
adjunto a. Cuando ejecuto el código, obtengo las propiedades de regreso a test1 pero no los campos reales.
Este es el código con el que estoy tratando de obtener los campos:
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);
Utilizo 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 abstraídas pero no los campos?
Edición: para obtener miembros privados del tipo base, tienes que:
typeof(T).BaseType.GetFields(...)
Editar de nuevo: Win.
Editar 3/22/13: utiliza Concat
lugar de Union
. Ya que estamos especificando BindingFlags.DeclaredOnly
y el Tipo de BindingFlags.DeclaredOnly
un tipo no puede igualarse, Union
no es necesario 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));
}
Enumeración de todos los campos de tipo, incluidos los miembros privados de las 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);
Las propiedades se heredan, los campos no. Los campos protegidos son visibles para las clases descendientes, pero no son heredados por ellos. En otras palabras, la clase descendiente en realidad tiene las propiedades de su clase base, pero solo puede ver los campos.
Puede usar este método de extensión para atravesar recursivamente la jerarquía de herencia de un tipo hasta el objeto, devolviendo efectivamente todos los campos del tipo y todos sus ancestros:
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;
}
}
(Sin probar, YMMV)
Si solo desea los nombres de propiedades y campos, use
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));
}
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 la siguiente:
B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString
Entonces, el tipo A
tiene dos campos; PrivateString
y ProtectedString
. Tipo B
tiene uno; ProtectedString
, que hereda de A
Si desea "llegar" a PrivateString
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 que tiene un campo llamado ProtectedString
, este campo aún no se declara en B
; se declara 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 al ejemplo de código, esto significa que el tipo test3
no contiene los campos test2
y test3
, ya que son privados al tipo test2
(me temo que la similitud de los nombres de campo y los nombres de tipo hace que la oración sea un tanto confusa). una