2008-09-18 10 views
173

dieser Klasse gegebenSuchen Sie ein privates Feld mit Reflection?

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

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

Ich möchte das private Element _bar finden, die ich mit einem Attribut markieren. Ist das möglich?

Ich habe dies mit Eigenschaften getan, wo ich nach einem Attribut gesucht habe, aber nie ein privates Mitglied Feld.

Was sind die Bindungsflags, die ich einstellen muss, um die privaten Felder zu bekommen?

+0

@Nescio: Können Sie Warum sollten Sie diesen Ansatz verfolgen? ...die Vorteile? Oder einfach Präferenz? :) – IAbstract

Antwort

212

Verwenden BindingFlags.NonPublic und BindingFlags.Instance Flaggen

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

Ich konnte das nur erreichen, indem ich auch das bindende Flag "BindingFlags.Instance" lieferte. –

+8

Ich würde gerne meine Antwort löschen, aber es ist markiert "akzeptiert". –

+1

Ich habe deine Antwort behoben. Es ist sonst zu verwirrend. Abe Heidebrechts Antwort war die vollständigste. –

4

Ja, jedoch müssen Sie Ihre Binding-Flags so einstellen, dass sie nach privaten Feldern suchen (wenn Sie nach dem Mitglied außerhalb der Klasseninstanz suchen).

Die Bindung Flagge Sie brauchen, ist: System.Reflection.BindingFlags.NonPublic

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

Ich werde den Namen des Feldes nicht kennen. Ich möchte es ohne den Namen finden und wenn das Attribut darauf steht. –

+0

Um den Feldnamen zu finden, ist es in Visual Studio einfach. Setzen Sie den Haltepunkt auf der Variablen, zeigen Sie deren Felder an (einschließlich des privaten, normalerweise mit m_fieldname gestartet). Ersetzen Sie den m_fieldname in dem obigen Befehl. –

156

Sie es genau wie mit einer Eigenschaft tun:

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

Sorry für extreme Nekro-Posting, aber das hat mich abgeworfen. GetCustomAttributes (Type) gibt NULL nicht zurück, wenn das Attribut nicht gefunden wird, es gibt einfach ein leeres Array zurück. – amnesia

24

Eine Sache, die Sie berücksichtigen müssen, wenn Sie über Priva nachdenken Wenn Ihre Anwendung in mittlerer Vertrauenswürdigkeit ausgeführt wird (z. B. wenn Sie in einer gemeinsam genutzten Hosting-Umgebung arbeiten), wird sie nicht gefunden. Die Option BindingFlags.NonPublic wird einfach ignoriert.

+0

jammycakes können Sie bitte ein Beispiel für Shared Hosting-Umgebung geben? Ich denke, dass ich mit mehreren Apps ist, was du bekommst? –

+0

Ich spreche darüber, wo IIS auf der Ebene machine.config auf teilweise Vertrauen gesperrt ist. Normalerweise finden Sie dies nur auf billigen und bösartigen Shared-Web-Hosting-Pläne in diesen Tagen (die ich nicht mehr benutze) - wenn Sie die volle Kontrolle über Ihren Server haben, dann wird es nicht wirklich relevant sein, da das volle Vertrauen ist Standard. – jammycakes

2

Ich bin bei der Suche nach diesem auf Google über dieses gestoßen, also merke ich, dass ich einen alten Pfosten stoße. Das GetCustomAttributes erfordert jedoch zwei Parameter.

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

Der zweite Parameter gibt an, ob oder nicht Sie wollen die Vererbungshierarchie

29

Get Privatvariablenwert mit Reflexion suchen:

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

Sollwert für die private Variable Reflexion:

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

Dabei ist objectForFooClass eine Nicht-Null-Instanz für die Klassenart Foo.

+0

Ähnliche Antwort beschreibt einfach zu benutzende Funktion 'GetInstanceField (typeof (YourClass), instance," someString ") als String' [Wie erhalten Sie den Wert des privaten Feldes in C#?] (Http://StackOverflow.com/A/3303182) –

5

Ich benutze diese Methode persönlich

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

Hier einige Erweiterungsmethoden für einfache get ist und setzen private Felder und Eigenschaften (Eigenschaften mit Setter):

Verwendungsbeispiel:

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 

Code:

/// <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

Sie können eine Erweiterungsmethode haben kein privates Feld für jede Art zu erhalten:

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

Und dann ein privates Feld eines beliebigen Typen zuzugreifen:

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

Alter, das war PERFEKT für den Zugriff auf eine geschützte Variable, ohne sie in meinem Code NLua ausgesetzt! Genial! – tayoung