Converti un'espressione > a un'espressione > in modo che T sia un membro di T1

c# expression-trees lambda

Domanda

Abbiamo un'entità di tipo T1 che ha un membro di tipo T qualcosa come questo :

public class T1
{
    public T Member{get;set;}
}

L'utente può usare la nostra interfaccia utente per darci un filtro su T e lo abbiamo tradotto in un'espressione di una funzione che ottiene una T e restituisce bool (Expression<Func<T,bool>>)

Mi piacerebbe sapere che è possibile convertire questo in un'espressione di una funzione che ottiene T1 e restituisce bool.

In realtà mi piacerebbe convertire questo:

(t=>t.Member1==someValue && t.Member2==someOtherValue);

a questa :

(t1=>t1.Member.Member1==someValue && t1.Member.Member2==someOtherValue);

Risposta accettata

Puoi farlo con un paio di modi.

Primo e più semplice: usa Expression.Invoke

Expression<Func<T, bool>> exprT = t.Member1==someValue && t.Member2==someOtherValue
ParameterExpression p = Expression.Parameter(typeof(T1));
var expr = Expression.Invoke(expr, Expression.PropertyOrField(p, "Member"));
Expression<Func<T1, bool>> exprT1 = Expression.Lambda<Func<T1, bool>>(expr, p);

ma in questo caso non ottieni

t1 => (t=>(t.Member1==someValue && t.Member2==someOtherValue))(t1.Member), 

invece di

(t1=>t1.Member.Member1==someValue && t1.Member.Member2==someOtherValue);

Per la sostituzione è possibile utilizzare la classe ExpressionVisitor come

    class V : ExpressionVisitor
    {
        public ParameterExpression Parameter { get; private set; }
        Expression m;
        public V(Type parameterType, string member)
        {
            Parameter = Expression.Parameter(parameterType);
            this.m = Expression.PropertyOrField(Parameter, member);
        }
        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (node.Type == m.Type)
            {
                return m;
            }
            return base.VisitParameter(node);
        }
    }

e usarlo

var v = new V(typeof(T1), "Member");
var exprT1 = Expression.Lambda<Func<T1, bool>>(v.Visit(exprT.Body), v.Parameter);

Risposta popolare

Dato

public class MyClass
{
    public MyInner Member { get; set; }
}

public class MyInner
{
    public string Member1 { get; set; }
    public string Member2 { get; set; }
}

più

public static Expression<Func<TOuter, bool>> Replace<TOuter, TInner>(Expression<Func<TInner, bool>> exp, Expression<Func<TOuter, TInner>> outerToInner)
{
    var body2 = new ExpressionReplacer { From = exp.Parameters[0], To = outerToInner.Body }.Visit(exp.Body);
    var lambda2 = Expression.Lambda<Func<TOuter, bool>>(body2, outerToInner.Parameters);
    return lambda2;
}

e

public class ExpressionReplacer : ExpressionVisitor
{
    public Expression From;
    public Expression To;

    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (node == From)
        {
            return base.Visit(To);
        }

        return base.VisitParameter(node);
    }
}

puoi

// The initial "data"
string someValue = "Foo";
string someOtherValue = "Bar";
Expression<Func<MyInner, bool>> exp = t => t.Member1 == someValue && t.Member2 == someOtherValue;
Expression<Func<MyClass, MyInner>> outerToInner = u => u.Member;

// The "new" expression
Expression<Func<MyClass, bool>> result = Replace(exp, outerToInner);

La classe ExpressionReplacer sostituisce un parametro di un'espressione con un'altra espressione, mentre il metodo Replace utilizza ExpressionReplacer e quindi ricrea una nuova espressione.



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é