2008-09-18 14 views
173

Teniendo en cuenta esta claseBusque un campo privado con Reflection?

class Foo 
{ 
    // Want to find _bar with reflection 
    [SomeAttribute] 
    private string _bar; 

    public string BigBar 
    { 
     get { return this._bar; } 
    } 
} 

Quiero encontrar el elemento _bar privada que voy a marcar con un atributo. ¿Es eso posible?

He hecho esto con propiedades donde he buscado un atributo, pero nunca un campo de miembro privado.

¿Cuáles son las banderas de encuadernación que necesito establecer para obtener los campos privados?

+0

@Nescio: ¿Puede usted ampliar por qué tomaría ese enfoque? ...¿los beneficios? ¿O simplemente preferencia? :) – IAbstract

Respuesta

212

Uso BindingFlags.NonPublic y BindingFlags.Instance banderas

FieldInfo[] fields = myType.GetFields(
         BindingFlags.NonPublic | 
         BindingFlags.Instance); 
+7

Solo pude hacer que esto funcionara al suministrar también el indicador de enlace "BindingFlags.Instance". –

+8

Con gusto eliminaré mi respuesta, pero está marcada como "aceptada". –

+1

He corregido tu respuesta. De lo contrario, es demasiado confuso. Sin embargo, la respuesta de Abe Heidebrecht fue la más completa. –

4

Sí, sin embargo, deberá establecer sus banderas de Enlazado para buscar campos privados (si busca el miembro fuera de la instancia de clase).

La bandera de unión que se necesita es: System.Reflection.BindingFlags.NonPublic

14
typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance) 
+0

No sabré el nombre del campo. Quiero encontrarlo sin el nombre y cuando el atributo está en él. –

+0

Para encontrar el nombre del campo, es fácil de hacer en Visual Studio. Establezca el punto de interrupción en la variable, vea sus campos (incluido el privado, generalmente iniciado con m_fieldname). Reemplace ese m_fieldname en el comando de arriba. –

156

Puede hacerlo al igual que con una propiedad:

FieldInfo fi = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance); 
if (fi.GetCustomAttributes(typeof(SomeAttribute)) != null) 
    ... 
+2

Lo siento por necro-publicación extrema, pero esto me tiró. GetCustomAttributes (Type) no devolverá null si el atributo no se encuentra, simplemente devuelve una matriz vacía. – amnesia

24

Una cosa que debe tener en cuenta al reflexionar sobre priva Los miembros son que si su aplicación se ejecuta en confianza media (como, por ejemplo, cuando se ejecuta en un entorno de alojamiento compartido), no los encontrará: la opción BindingFlags.NonPublic simplemente se ignorará.

+0

jammycakes ¿podría dar un ejemplo del entorno de alojamiento compartido? estoy pensando que con múltiples aplicaciones es lo que estás obteniendo? –

+0

Me refiero a que IIS está bloqueado a confianza parcial en el nivel machine.config. Por lo general, esto solo se encuentra en los planes de alojamiento web compartido baratos y desagradables (de los que ya no uso); si tienes control total sobre tu servidor, entonces no será relevante ya que la confianza total es la misma. defecto. – jammycakes

2

Me encontré con esto mientras buscaba esto en google, así que me doy cuenta de que estoy superando una publicación anterior. Sin embargo, GetCustomAttributes requiere dos params.

typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance) 
.Where(x => x.GetCustomAttributes(typeof(SomeAttribute), false).Length > 0); 

El segundo parámetro especifica si desea buscar en la jerarquía de herencia

29

Obtener el valor utilizando la reflexión de variable privada:

var _barVariable = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(objectForFooClass); 

Valor de ajuste para la variable privada utilizando Reflexión:

typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(objectForFoocClass, "newValue"); 

Donde objectForFooClass es una instancia no nula para el tipo de clase Foo.

+0

Respuesta similar describe la función fácil de usar 'GetInstanceField (typeof (YourClass), instance," someString ") como string' [¿Cómo obtener el valor del campo privado en C#?] (Http://stackoverflow.com/a/3303182) –

5

utilizo este método personalmente

if (typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Any(c => c.GetCustomAttributes(typeof(SomeAttribute), false).Any())) 
{ 
    // do stuff 
} 
3

Aquí es algunos métodos de extensión para sencillo obtener y definir los campos privados y propiedades (propiedades con colocador): Ejemplo

uso:

public class Foo 
    { 
     private int Bar = 5; 
    } 

    var targetObject = new Foo(); 
    var barValue = targetObject.GetMemberValue("Bar");//Result is 5 
    targetObject.SetMemberValue("Bar", 10);//Sets Bar to 10 

Código:

/// <summary> 
    /// Extensions methos for using reflection to get/set member values 
    /// </summary> 
    public static class ReflectionExtensions 
    { 
     /// <summary> 
     /// Gets the public or private member using reflection. 
     /// </summary> 
     /// <param name="obj">The source target.</param> 
     /// <param name="memberName">Name of the field or property.</param> 
     /// <returns>the value of member</returns> 
     public static object GetMemberValue(this object obj, string memberName) 
     { 
      var memInf = GetMemberInfo(obj, memberName); 

      if (memInf == null) 
       throw new System.Exception("memberName"); 

      if (memInf is System.Reflection.PropertyInfo) 
       return memInf.As<System.Reflection.PropertyInfo>().GetValue(obj, null); 

      if (memInf is System.Reflection.FieldInfo) 
       return memInf.As<System.Reflection.FieldInfo>().GetValue(obj); 

      throw new System.Exception(); 
     } 

     /// <summary> 
     /// Gets the public or private member using reflection. 
     /// </summary> 
     /// <param name="obj">The target object.</param> 
     /// <param name="memberName">Name of the field or property.</param> 
     /// <returns>Old Value</returns> 
     public static object SetMemberValue(this object obj, string memberName, object newValue) 
     { 
      var memInf = GetMemberInfo(obj, memberName); 


      if (memInf == null) 
       throw new System.Exception("memberName"); 

      var oldValue = obj.GetMemberValue(memberName); 

      if (memInf is System.Reflection.PropertyInfo) 
       memInf.As<System.Reflection.PropertyInfo>().SetValue(obj, newValue, null); 
      else if (memInf is System.Reflection.FieldInfo) 
       memInf.As<System.Reflection.FieldInfo>().SetValue(obj, newValue); 
      else 
       throw new System.Exception(); 

      return oldValue; 
     } 

     /// <summary> 
     /// Gets the member info 
     /// </summary> 
     /// <param name="obj">source object</param> 
     /// <param name="memberName">name of member</param> 
     /// <returns>instanse of MemberInfo corresponsing to member</returns> 
     private static System.Reflection.MemberInfo GetMemberInfo(object obj, string memberName) 
     { 
      var prps = new System.Collections.Generic.List<System.Reflection.PropertyInfo>(); 

      prps.Add(obj.GetType().GetProperty(memberName, 
               System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | 
               System.Reflection.BindingFlags.FlattenHierarchy)); 
      prps = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where(prps,i => !ReferenceEquals(i, null))); 
      if (prps.Count != 0) 
       return prps[0]; 

      var flds = new System.Collections.Generic.List<System.Reflection.FieldInfo>(); 

      flds.Add(obj.GetType().GetField(memberName, 
              System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | 
              System.Reflection.BindingFlags.FlattenHierarchy)); 

      //to add more types of properties 

      flds = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where(flds, i => !ReferenceEquals(i, null))); 

      if (flds.Count != 0) 
       return flds[0]; 

      return null; 
     } 

     [System.Diagnostics.DebuggerHidden] 
     private static T As<T>(this object obj) 
     { 
      return (T)obj; 
     } 
    } 
1

Usted puede tener un método de extensión para obtener cualquier campo privado de cualquier tipo:

public static T GetFieldValue<T>(this object obj, string name) { 
    var field = obj.GetType().GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 
    return (T)field?.GetValue(obj); 
} 

y luego acceder a un campo privado de un tipo arbitrario:

Foo foo = new Foo(); 
string c = foo.GetFieldValue<string>("_bar"); 
+1

Amigo, esto fue PERFECTO para acceder a una variable protegida sin exponerlo a NLua en mi código. ¡Increíble! – tayoung

Cuestiones relacionadas