Comprendre l'arbre des expressions et l'évaluation des paramètres

c# expression-trees

Question

J'essaie de modifier un arbre d'expression qui crée de manière dynamique une expression Contains qui aboutit à un résultat SQL similaire à

P IN (123, 124, 125, 200, 201)

pour vérifier à la place, effectuez des vérifications de plage, ce qui aboutit finalement à un SQL comme

(P >= 123 AND P <= 125) OR (P >= 200 AND P <= 201)

Je base ma solution sur ce post .

static public Expression<Func<TElement, bool>> 
BuildContainsExpression<TElement, TValue>(
    Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values)
{
    // Removed for post: Input checks and edge cases

    var equals = 
      values.Select(value => 
       (Expression)Expression.Equal(valueSelector.Body, 
                                    Expression.Constant(value, typeof(TValue))));

    var body = equals.Aggregate<Expression>((accumulate, equal) => 
                                             Expression.Or(accumulate, equal));

    return Expression.Lambda<Func<TElement, bool>>(body, p);
}

Je peux faire fonctionner la vérification de plage si je fournis la valeur à des fins de comparaison:

long testValue = 5;
List<KeyValuePair<int, int>> ranges = new List<KeyValuePair<int, int>>() 
{
    new KeyValuePair<long, long>(3, 6),
    new KeyValuePair<long, long>(10, 12),
    new KeyValuePair<long, long>(20, 20),
};

List<BinaryExpression> rangeExpressions = new List<BinaryExpression>();

foreach (var pair in ranges)
{
    var greaterThanOrEqual = 
        Expression.GreaterThanOrEqual(Expression.Constant(testValue), 
                                      Expression.Constant(pair.Key));

    var lessThanOrEqual = 
        Expression.LessThanOrEqual(Expression.Constant(testValue), 
                                   Expression.Constant(pair.Value));

    var inRange = Expression.AndAlso(greaterThanOrEqual, lessThanOrEqual);
    rangeExpressions.Add(inRange);
}

var final = 
    rangeExpressions.Aggregate<Expression>((a, b) => Expression.Or(a, b));

var result = Expression.Lambda<Func<bool>>(final).Compile()();

Cependant, je ne peux pas déterminer comment obtenir la valeur à comparer de l'expression transmise lorsque je dépose ce code dans la méthode à utiliser avec Linq. La signature de cette méthode est:

Expression<Func<TElement, bool>> 
BuildRangeExpression<TElement>(
    Expression<Func<TElement, long>> valueSelector, 
    IEnumerable<long> values)

et il s'utilise comme:

Expression<MyType, bool> match = 
    BuildRangeExpression<MyType, long>(my => my.ProductCode, productCodes);

var result = db.MyTypes.Where(match);

QUESTION

Comment puis-je évaluer

Expression<Func<TElement, long>> valueSelector

afin que je puisse utiliser la valeur passée dans BuildRangeExpression au lieu de ma valeur actuellement codée en dur

long testValue = 5;

Réponse acceptée

Je pense que le code de l'article de blog a exactement ce dont vous avez besoin: il vous suffit d'utiliser valueSelector.Body au lieu de votre Expression.Constant() et d'ajouter également le paramètre d'origine à l'expression générée:

public static Expression<Func<TElement, bool>>
    BuildRangeExpression<TElement, TValue>(
    Expression<Func<TElement, TValue>> valueSelector,
    IEnumerable<Tuple<TValue, TValue>> values)
{
    var p = valueSelector.Parameters.Single();

    var equals = values.Select(
        tuple =>
        Expression.AndAlso(
            Expression.GreaterThanOrEqual(
                valueSelector.Body, Expression.Constant(tuple.Item1)),
            Expression.LessThanOrEqual(
                valueSelector.Body, Expression.Constant(tuple.Item2))));

    var body = equals.Aggregate(Expression.OrElse);

    return Expression.Lambda<Func<TElement, bool>>(body, p);
}

Réponse populaire

Utilisez Expression.Parameter .

Créez un paramètre:

var param = Expression.Parameter(typeof(TElement), "arg")

Au lieu de Expression.Constant(testvalue) , vous devrez mettre param .

Ensuite, vous devez faire:

var result = Expression.Lambda<Func<TElement, bool>>(final, param).Compile() 


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