it-swarm.com.de

Finde ein privates Feld mit Reflection?

Angesichts dieser Klasse

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, das ich mit einem Attribut kennzeichnen möchte. Ist das möglich?

Ich habe dies mit Eigenschaften gemacht, bei denen ich nach einem Attribut gesucht habe, aber niemals nach einem privaten Mitgliedsfeld.

Welche Bindungsflags muss ich setzen, um die privaten Felder abzurufen?

208
David Basarab

Verwenden BindingFlags.NonPublic und BindingFlags.Instance Flaggen

FieldInfo[] fields = myType.GetFields(
                         BindingFlags.NonPublic | 
                         BindingFlags.Instance);
258
Bob King

Sie können dies wie bei einer Immobilie tun:

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

Rufen Sie den Wert der privaten Variablen mit Reflection ab:

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

Stellen Sie den Wert für die private Variable mit Reflection ein:

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

Wobei objectForFooClass eine Nicht-Null-Instanz für den Klassentyp Foo ist.

37
Suriya

Eine Sache, die Sie beachten müssen, wenn Sie über private Mitglieder nachdenken, ist, dass Ihre Anwendung, wenn sie mit mittlerer Vertrauenswürdigkeit ausgeführt wird (wie zum Beispiel in einer gemeinsam genutzten Hosting-Umgebung), diese nicht findet - die Die Option BindingFlags.NonPublic wird einfach ignoriert.

24
jammycakes
typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)
18
Darren Kopp

Schöne Syntax mit Erweiterungsmethode

Sie können auf jedes private Feld eines beliebigen Typs mit folgendem Code zugreifen:

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

Dazu müssen Sie eine Erweiterungsmethode definieren, die die Arbeit für Sie erledigt:

public static class ReflectionExtensions {
    public static T GetFieldValue<T>(this object obj, string name) {
        // Set the flags so that private and public fields from instances will be found
        var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
        var field = obj.GetType().GetField(name, bindingFlags);
        return (T)field?.GetValue(obj);
    }
}
11
Bruno Zell

Ich benutze diese Methode persönlich

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

Hier sind einige Erweiterungsmethoden zum einfachen Abrufen und Festlegen privater Felder und Eigenschaften (Eigenschaften mit Setter):

anwendungsbeispiel:

    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;
        }
    }
4
epsi1on

Ja, Sie müssen jedoch Ihre Binding-Flags setzen, um nach privaten Feldern zu suchen (wenn Sie das Mitglied außerhalb der Klasseninstanz suchen).

Das Bindungsflag, das Sie benötigen, lautet: System.Reflection.BindingFlags.NonPublic

4
mmattax

Ich bin darauf gestoßen, als ich auf Google danach gesucht habe, also stoße ich auf einen alten Beitrag. Für GetCustomAttributes sind jedoch zwei Parameter erforderlich.

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

Der zweite Parameter gibt an, ob Sie die Vererbungshierarchie durchsuchen möchten oder nicht

2
Gunner