Arbre d'expression C # pour appeler la méthode get de la propriété de la classe de base

.net-4.5 c# expression-trees reflection

Question

J'ai construit un arbre d'expression qui dérive les paramètres d'une classe et les appelle pour définir des valeurs dans une autre classe. Cela fonctionne très bien pour la plupart des types, mais il échoue sur un type dérivé. Si j'ai:

public class A
{
    public string MyString {get; set;}
}

et

public class B : A
{

}

Si j'utilise ce code de l'arbre d'expression (où value correspond à l'instance dérivée):

// Get the type of the object for caching and ExpressionTree purposes
var objectType = value.GetType();
// Define input parameter
var inputObject = Expression.Parameter( typeof( object ), "value" );

var properties = objectType.GetProperties( BindingFlags.Instance | BindingFlags.Public );
foreach (var property in properties)
{
    Expression.Property( Expression.ConvertChecked( inputObject, property.DeclaringType ), property.GetGetMethod() )
}

Je vais recevoir cette exception:

{System.ArgumentException: The method 'My.Namespace.A.get_MyString' is not a property accessor
at System.Linq.Expressions.Expression.GetProperty(MethodInfo mi)...

Qu'est-ce que je fais mal ici?

Réponse acceptée

Vous devez utiliser la propriété elle-même et non la méthode Getter:

foreach (var property in properties)
{
    Expression.Property( 
         Expression.ConvertChecked( inputObject, property.DeclaringType ),
         property);
}

Fondamentalement, vous devez utiliser cette méthode Property au lieu de cette méthode Property surchargée.

METTRE À JOUR

Pour l'approche GetGetMethod - Si var objectType égal à A type, cela fonctionne. Si cela correspond au type B , cela ne fonctionne pas.

Je suppose que le problème se trouve dans property.DeclaringType . Dans les deux cas, il s'agit d' A type, comme propriété déclarée dans celui-ci. Mais ce code renverra ReflectedType différent pour la même propriété:

var reflectingTypeForA = typeof(A).GetProperty("MyString").GetGetMethod().ReflectedType;
var reflectingTypeForB = typeof(B).GetProperty("MyString").GetGetMethod().ReflectedType;

Pour A il retourne A , et pour le type B il retourne B Mon hypothèse est que, dans le cas B , la logique Expression.Property vérifie que property.DeclaringType est A , mais GetGetMethod a ReflectedType égal à B et pense donc qu'il s'agit de la propriété d'un autre objet. Je n'ai pas de preuves pour cela, mais seuls ces membres sont différents entre deux appels GetGetMethod

UPDATE2

Voici un code utilisé par Expression.Property (méthode MethodInfo):

private static PropertyInfo GetProperty(MethodInfo mi)
{
    Type type = mi.DeclaringType;
    BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic;
    flags |= (mi.IsStatic) ? BindingFlags.Static : BindingFlags.Instance;
    PropertyInfo[] props = type.GetProperties(flags);
    foreach (PropertyInfo pi in props)
    {
        if (pi.CanRead && CheckMethod(mi, pi.GetGetMethod(true)))
        {
            return pi;
        }
        if (pi.CanWrite && CheckMethod(mi, pi.GetSetMethod(true)))
        {
            return pi;
        }
    }
    throw new SomeException();
}

private static bool CheckMethod(MethodInfo method, MethodInfo propertyMethod) { 
    if (method == propertyMethod) {
        return true; 
    } 
    // If the type is an interface then the handle for the method got by the compiler will not be the
    // same as that returned by reflection. 
    // Check for this condition and try and get the method from reflection.
    Type type = method.DeclaringType;
    if (type.IsInterface && method.Name == propertyMethod.Name && type.GetMethod(method.Name) == propertyMethod) {
        return true; 
    }
    return false; 
} 

Le problème est dans cette ligne:

if (method == propertyMethod) {
    return true; 
} 

Lorsque vous obtenez MethodInfo par GetGetMethod à partir de type A , il est différent de MethodInfo à partir de type B et cette vérification renvoie false. Cet exemple retourne également false:

var propertyAGetter = typeof(A).GetProperty("MyString").GetGetMethod();
var propertyBGetter = typeof(B).GetProperty("MyString").GetGetMethod();
bool areTheSame = propertyAGetter == propertyBGetter; // it equals to false



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi