L'arbre d'expression avec l'héritage de propriété provoque une exception d'argument

.net expression-trees linq

Question

Suite à cet article: texte du lien J'essaie de créer un arbre d'expression qui référence la propriété d'une propriété. Mon code ressemble à ceci:

public interface IFoo
{
    void X {get;set;}
}

public interface IBar : IFoo
{
    void Y {get;set;}
}

public interface IFooBarContainer
{
    IBar Bar {get;set;}
}

public class Filterer
{
     //Where T = "IFooBarContainer"
     public IQueryable<T> Filter<T>(IEnumerable<T> collection)
     {
              var argument = Expression.Parameter(typeof (T), "item");

              //...

               //where propertyName = "IBar.X";
               PropertyOfProperty(argument, propertyName); 
     }

        private static MemberExpression PropertyOfProperty(Expression expr, string propertyName)
        {
            return propertyName.Split('.').Aggregate<string, MemberExpression>(null, (current, property) => Expression.Property(current ?? expr, property));
        }
}

Je reçois l'exception:

System.ArgumentException: la propriété d'instance 'X' n'est pas définie pour le type 'IBar'

ReSharper a transformé le code du lien ci-dessus en instruction condensée dans mon exemple. Les deux formes de la méthode ont renvoyé la même erreur.

Si je fais référence à IBar.Y la méthode n’échoue pas.

Réponse acceptée

La propriété à laquelle vous essayez d'accéder n'est pas IBar.X , c'est IFoo.X La méthode Expression.Property attend le type réel qui déclare la propriété, pas un sous-type. Si vous n'êtes pas convaincu, essayez ça:

var prop = typeof(IBar).GetProperty("X");

Il retourne null (uniquement parce IBar est une interface; cela fonctionnerait pour une classe)

Je pense que le moyen le plus simple de le faire fonctionner est de créer une méthode d'assistance pour résoudre la propriété réelle, en remontant récursivement la hiérarchie des types:

private PropertyInfo GetProperty(Type type, string propertyName)
{
    PropertyInfo prop = type.GetProperty(propertyName);
    if (prop == null)
    {
        var baseTypesAndInterfaces = new List<Type>();
        if (type.BaseType != null) baseTypesAndInterfaces.Add(type.BaseType);
        baseTypesAndInterfaces.AddRange(type.GetInterfaces());
        foreach(Type t in baseTypesAndInterfaces)
        {
            prop = GetProperty(t, propertyName);
            if (prop != null)
                break;
        }
    }
    return prop;
}

Vous pouvez ensuite réécrire votre PropertyOfProperty comme suit:

private static MemberExpression PropertyOfProperty(MemberExpression expr, string propertyName)
{
    return propertyName
               .Split('.')
               .Aggregate<string, MemberExpression>(
                   expr,
                   (current, property) =>
                       Expression.Property(
                           current,
                           GetProperty(current.Type, property)));
}


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow