c# - propiedades - Reflejando un campo privado desde una clase base
modificadores de acceso visual basic (5)
Aquí está la estructura:
MyClass: SuperClass2
SuperClass2: SuperClass1
superClass2 está en Product.Web y SuperClass1 está en el ensamblado .NET System.Web
Estoy tratando de forzar un valor en un campo bool privado en SuperClass1. Pero no importa lo que intente, no puedo hacer que los campos vuelvan de la reflexión.
Estoy usando el siguiente código con diferentes combinaciones de BindingFlag pero nada ha funcionado hasta ahora. SuperClass1 es una clase abstracta.
((SuperClass1)this).GetType().GetFields(System.Reflection.BindingFlags.NonPublic);
Notas: Cuando uso GetProperties (), obtengo una buena lista grande, pero cuando especifico cualquier marca de enlace no obtengo nada aunque haya propiedades coincidentes. ¿Cual es el trato?
Además, el campo no está marcado como interno.
Obvisouly estaría usando GetField (nombre de cadena, BindingFlags) pero ni siquiera puedo hacer que GetFlags () funcione.
Actualización : he intentado agregar BindingFlags.Instance como se sugiere, pero no funciona (como se esperaba). Recupero 2 campos que provienen de la clase de la que SuperClass1 hereda. Devuelve un valor nulo cuando se usa con GetField (nombre de cadena, indicadores)
Aquí está el código para la clase base para la que estoy tratando de obtener el campo
public abstract class BaseValidator : Label, IValidator
{
private bool propertiesChecked;
...
}
Creo que necesitas agregar la bandera System.Reflection.BindingFlags.Instance. Utilizar | Combinarlo con la bandera no pública.
EDITAR:
Parece que BrokenGlass tiene razón. Escribí la siguiente prueba rápida.
var fields = test.GetType().BaseType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var field in fields)
{
System.Console.WriteLine(field.Name);
}
Informa correctamente el campo que estabas buscando. (La prueba se deriva de BaseValidator)
De forma similar a la solución de BrokenGlass, puedes hacer esto para que sea un poco más genérico:
class Base { private int _baseField; }
class Derived : Base { }
class Mine : Derived { }
Y entonces:
Type t = typeof(Mine);
FieldInfo fi = null;
while (t != null)
{
fi = t.GetField("_baseField", BindingFlags.Instance | BindingFlags.NonPublic);
if (fi != null) break;
t = t.BaseType;
}
if (fi == null)
{
throw new Exception("Field ''_baseField'' not found in type hierarchy.");
}
Como método de utilidad:
public static void SetField(object target, string fieldName, object value)
{
if (target == null)
{
throw new ArgumentNullException("target", "The assignment target cannot be null.");
}
if (string.IsNullOrEmpty(fieldName))
{
throw new ArgumentException("fieldName", "The field name cannot be null or empty.");
}
Type t = target.GetType();
FieldInfo fi = null;
while (t != null)
{
fi = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
if (fi != null) break;
t = t.BaseType;
}
if (fi == null)
{
throw new Exception(string.Format("Field ''{0}'' not found in type hierarchy.", fieldName));
}
fi.SetValue(target, value);
}
Y entonces:
Mine m = new Mine();
SetField(m, "_baseField", 10);
Puede subir manualmente en la cadena de herencia para obtener los campos base:
Dadas estas clases:
class SuperClass1
{
private int myField;
}
class SuperClass2 : SuperClass1
{
}
class MyClass : SuperClass2
{
}
Esto debería funcionar:
var myObj = new MyClass();
var myField = typeof(MyClass).BaseType
.BaseType
.GetField("myField", BindingFlags.Instance | BindingFlags.NonPublic);
Hay una solución más genérica en esta respuesta SO: No obtener campos de GetType (). GetFields with BindingFlag.Default
Si la jerarquía es estática, la forma más sencilla de hacer esto:
var field = typeof(SuperClass1).GetField("_privateBaseField",System.Reflection.BindingFlags.NonPublic);
Método de extensión:
/// <summary>
/// Returns the FieldInfo matching ''name'' from either type ''t'' itself or its most-derived
/// base type (unlike ''System.Type.GetField''). Returns null if no match is found.
/// </summary>
public static FieldInfo GetPrivateField(this Type t, String name)
{
const BindingFlags bf = BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.DeclaredOnly;
FieldInfo fi;
while ((fi = t.GetField(name, bf)) == null && (t = t.BaseType) != null)
;
return fi;
}