L'albero delle espressioni con ereditarietà delle proprietà causa un'eccezione di argomento

.net expression-trees linq

Domanda

Seguendo questo post: link text Sto tentando di creare un albero di espressioni che faccia riferimento alla proprietà di una proprietà. Il mio codice assomiglia a questo:

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

Ho ricevuto l'eccezione:

System.ArgumentException: la proprietà istanza 'X' non è definita per il tipo 'IBar'

ReSharper ha trasformato il codice nel link sopra nell'istruzione condensata nel mio esempio. Entrambe le forme del metodo hanno restituito lo stesso errore.

Se faccio riferimento a IBar.Y il metodo non fallisce.

Risposta accettata

La proprietà a cui stai tentando di accedere non è IBar.X , è IFoo.X Il metodo Expression.Property prevede il tipo effettivo che dichiara la proprietà, non un sottotipo. Se non sei convinto, prova questo:

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

Restituisce null (solo perché IBar è un'interfaccia, funzionerebbe per una classe)

Penso che il modo più semplice per farlo funzionare sia creare un metodo di supporto per risolvere la proprietà effettiva, risalendo la gerarchia di tipi in modo ricorsivo:

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

È quindi possibile riscrivere PropertyOfProperty come segue:

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


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché