web-dev-qa-db-fra.com

Trouver un champ privé avec Reflection?

Étant donné cette classe

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

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

Je veux trouver l'élément privé _bar que je marquerai avec un attribut. Est-ce possible?

J'ai fait cela avec des propriétés pour lesquelles j'ai cherché un attribut, mais jamais un champ membre privé.

Quels sont les indicateurs de liaison que je dois définir pour obtenir les champs privés?

208
David Basarab

Utiliser les drapeaux BindingFlags.NonPublic et BindingFlags.Instance

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

Vous pouvez le faire comme avec une propriété:

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

Obtenir la valeur de la variable privée en utilisant Reflection:

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

Définissez la valeur de la variable privée à l'aide de Reflection:

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

Où objectForFooClass est une instance non nulle pour le type de classe Foo.

37
Suriya

Lorsque vous réfléchissez aux membres privés, vous devez savoir que si votre application est exécutée dans une confiance moyenne (comme, par exemple, lorsque vous utilisez un environnement d'hébergement partagé), elle ne les trouvera pas - la L'option BindingFlags.NonPublic sera simplement ignorée.

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

Belle syntaxe avec méthode d'extension

Vous pouvez accéder à n’importe quel champ privé d’un type quelconque avec un code comme celui-ci:

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

Pour cela, vous devez définir une méthode d'extension qui effectuera le travail à votre place:

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

J'utilise cette méthode personnellement

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

Voici quelques méthodes d'extension pour les champs et propriétés privés get et set simples (propriétés avec setter):

exemple d'utilisation:

    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

Oui, toutefois, vous devrez définir vos indicateurs de liaison pour rechercher des champs privés (si vous recherchez le membre en dehors de l'instance de la classe).

L’indicateur de liaison dont vous aurez besoin est: System.Reflection.BindingFlags.NonPublic

4
mmattax

Je suis tombé sur cela en cherchant ceci sur google, alors je me rends compte que je cogne un ancien post. Cependant, GetCustomAttributes nécessite deux paramètres.

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

Le deuxième paramètre spécifie si vous souhaitez ou non rechercher dans la hiérarchie d'héritage.

2
Gunner