web-dev-qa-db-fra.com

Refléter un champ privé à partir d'une classe de base

Voici la structure:

MyClass: SuperClass2

SuperClass2: SuperClass1

superClass2 est dans Product.Web et SuperClass1 dans .NET System.Web Assembly.

J'essaie de forcer une valeur dans un champ bool privé sur SuperClass1. Mais peu importe ce que j'essaie, je ne peux pas faire revenir les champs de la réflexion.

J'utilise le code suivant avec différentes combinaisons de BindingFlag mais rien n'a fonctionné jusqu'à présent. SuperClass1 est une classe abstraite.

((SuperClass1)this).GetType().GetFields(System.Reflection.BindingFlags.NonPublic);

Notes: Lorsque j'utilise GetProperties (), je récupère une grande liste de Nice, mais lorsque je spécifie un bindingglags, je ne reçois rien, même s'il existe des propriétés correspondantes. Quel est le problème?

En outre, le champ n'est pas marqué comme interne

Bien évidemment, j'utiliserais GetField (nom de chaîne, BindingFlags) mais je ne parviens même pas à faire fonctionner GetFlags ().

Mise à jour : J'ai essayé d'ajouter BindingFlags.Instance comme suggéré mais cela ne fonctionne pas (comme prévu de toute façon). Je récupère 2 champs qui proviennent de la classe dont SuperClass1 hérite. Retourne null lorsqu'il est utilisé avec GetField (nom de chaîne, Flags)

Voici le code de la classe de base que j'essaie d'obtenir le champ

public abstract class BaseValidator : Label, IValidator
  {
    private bool propertiesChecked;
...
}
20
Dustin Davis

Vous pouvez manuellement monter dans la chaîne d'héritage pour obtenir les champs de base:

Étant donné ces cours:

class SuperClass1
{
    private int myField;
}

class SuperClass2 : SuperClass1
{
}

class MyClass : SuperClass2
{

}

Cela devrait fonctionner:

var myObj = new MyClass();
var myField = typeof(MyClass).BaseType
                             .BaseType
                             .GetField("myField", BindingFlags.Instance | BindingFlags.NonPublic);

Il y a une solution plus générique dans cette SO réponse: Les champs de GetType () ne sont pas récupérés. GetFields avec BindingFlag.Default

33
BrokenGlass

Dans le même esprit que la solution de BrokenGlass, vous pouvez le faire pour le rendre un peu plus générique:

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

Et alors:

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

Comme méthode d'utilité:

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

Et alors:

Mine m = new Mine();

SetField(m, "_baseField", 10);
7
Shibumi

Je pense que vous devez ajouter l'indicateur System.Reflection.BindingFlags.Instance. Utiliser | pour le combiner avec le drapeau NonPublic.

MODIFIER:

On dirait que BrokenGlass a le droit. J'ai écrit le test rapide suivant.

var fields = test.GetType().BaseType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var field in fields)
{
     System.Console.WriteLine(field.Name);
}

Il indique correctement le champ que vous recherchez. (Le test est dérivé de BaseValidator)

3
Nathanael

Méthode d'extension:

/// <summary>
/// Returns the FieldInfo matching 'name' from either type 't' itself or its most-derived 
/// base type (unlike 'System.Type.GetField'). Returns null if no match is found.
/// </summary>
public static FieldInfo GetPrivateField(this Type t, String name)
{
    const BindingFlags bf = BindingFlags.Instance | 
                            BindingFlags.NonPublic | 
                            BindingFlags.DeclaredOnly;

    FieldInfo fi;
    while ((fi = t.GetField(name, bf)) == null && (t = t.BaseType) != null)
        ;
    return fi;
}
2
Glenn Slayden

Si la hiérarchie est statique, la manière la plus simple de procéder est la suivante:

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