2011-08-05 11 views
19

Aquí está la estructura:Reflejando un campo privado de una clase base

MiClase: SuperClass2

SuperClass2: SuperClass1

superClass2 está en Product.Web y SuperClass1 está en el .NET System.Web ensamblaje

Estoy tratando de forzar un valor en un campo bool privado en SuperClass1. Pero no importa lo que intento, 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() regrese una buena lista grande, pero cuando especifico ningún BindingFlags no consigo nada a pesar de que existen propiedades coincidentes. ¿Cual es el trato?

Además, el campo no está marcado interno

obvisouly iba a usar GetField (nombre de la cadena, BindingFlags) pero no puede incluso conseguir GetFlags() para trabajar.

actualización: He intentado añadir BindingFlags.Instance como se sugiere, pero no funciona (como se espera de todos modos). Recupero 2 campos que provienen de la clase heredada de SuperClass1. Devuelve un valor nulo cuando se usa con GetField (nombre de la cadena, Banderas)

Aquí es el código de la clase base que estoy tratando de llegar al campo de

public abstract class BaseValidator : Label, IValidator 
    { 
    private bool propertiesChecked; 
... 
} 
+0

Lo siento por una pregunta estúpida, pero ¿por qué haces esto? :) – sll

+2

Gran pregunta. Debido a Product.Web.SuperClass2, tengo que hacer esto como un trabajo para implementar el soporte para una característica que ya deberían admitir, pero no lo hacen. Básicamente, la API tiene un método virtual, pero SIEMPRE llama a la implementación base. Así que necesito cambiar el valor del campo para que no haga ciertas comprobaciones para que pueda ejecutar mi código. –

+1

Por favor, no pregunte "¿por qué quieres hacer esto?" - No es útil o constructivo - hay un millón de razones válidas para hacer esto, y todas son diferentes. Obviamente, el código huele, pero el dogma no va a ayudar a los 900 mil de nosotros que serán arrojados aquí a través de Google. – BrainSlugs83

Respuesta

30

se puede ir manualmente en la cadena de herencia para obtener los campos de la 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: Not getting fields from GetType().GetFields with BindingFlag.Default

+0

Eso lo hizo. No vi BaseType allí. Ahora esperemos que esta aventura solucione mi problema original ... –

3

Creo que es necesario agregar la System.Reflection .BindingFlags.Instance flag. Uso | para combinarlo con el indicador NonPublic.

EDIT:

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 estaba buscando.(Test se deriva de BaseValidator)

+0

Ya lo he intentado. –

+0

Hay un permiso que necesita para reflejar los campos privados. ¿Podría proporcionar el campo al que está intentando acceder y la clase de la que proviene en System.Web? (Definitivamente necesitarás el indicador de instancia para que esto funcione). – Nathanael

+0

"System.Web.UI.WebControls.BaseValidator" y quiero establecer propertiesChecked –

7

En una línea similar a la solución de BrokenGlass, usted podría hacer esto para que sea un poco más genérica:

class Base { private int _baseField; } 
class Derived : Base { } 
class Mine : Derived { } 

Y luego:

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 luego:

Mine m = new Mine(); 

SetField(m, "_baseField", 10); 
0

Si la jerarquía es estática, la forma más sencilla de hacer esto: método

var field = typeof(SuperClass1).GetField("_privateBaseField",System.Reflection.BindingFlags.NonPublic); 
0

Extensión:

/// <summary> 
/// Includes private fields in base classes of 't' (unlike 'System.Type.GetField') 
/// </summary> 
public static FieldInfo GetPrivateField(this Type t, String name) 
{ 
    FieldInfo fi; 
    do 
     if ((fi = t.GetField(name, BindingFlags.Instance | 
            BindingFlags.NonPublic | 
            BindingFlags.DeclaredOnly)) != null) 
      return fi; 
    while ((t = t.BaseType) != null); 
    return null; 
} 
Cuestiones relacionadas