How to use an expression (from TDelegate) .Update Method

I created a repository using lambda expressions to filter my collections of entities. As a method parameter, I send Expression<Func<Case, bool>> exp . But inside the method, I would like to update the same expression with some global filters. I see that the expression object itself received the Update method, but I canโ€™t understand how it is implemented (and I canโ€™t find anything when searching the network).

 exp.Update(exp.Body, ???); 

Can anyone give an example?

EDIT: method definition: http://msdn.microsoft.com/en-us/library/ee378255.aspx

EDIT 2: This is my code (where I am trying to use. And):

 Expression<Func<Case, bool>> newExp = c => c.CaseStatusId != (int)CaseStatus.Finished var binExp = Expression.And(exp.Body, newExp.Body); ParameterExpression paramExp = Expression.Parameter(typeof(Expression<Func<Case, bool>>), "c"); return repository.Where(Expression.Lambda<Expression<Func<Case, bool>>>(binExp, new[] { paramExp }).Compile()).ToArray(); 

Failure with the following ArgumentException: lambda-type parameter must be obtained from System.Delegate

+5
source share
2 answers

I do not think the Update method can help you here. It only creates a new lambda, but does not update the original parameters with new ones, you have to do it manually. I would recommend having a visitor that replaces the parameter, then you can And expressions together.

In total you will get something like:

  private Case[] getItems(Expression<Func<Case, bool>> exp) { return repository.Where(AddGlobalFilters(exp).Compile()).ToArray(); } private Expression<Func<Case, bool>> AddGlobalFilters(Expression<Func<Case, bool>> exp) { // get the global filter Expression<Func<Case, bool>> newExp = c => c.CaseStatusId != (int)CaseStatus.Finished; // get the visitor var visitor = new ParameterUpdateVisitor(newExp.Parameters.First(), exp.Parameters.First()); // replace the parameter in the expression just created newExp = visitor.Visit(newExp) as Expression<Func<Case, bool>>; // now you can and together the two expressions var binExp = Expression.And(exp.Body, newExp.Body); // and return a new lambda, that will do what you want. NOTE that the binExp has reference only to te newExp.Parameters[0] (there is only 1) parameter, and no other return Expression.Lambda<Func<Case, bool>>(binExp, newExp.Parameters); } /// <summary> /// updates the parameter in the expression /// </summary> class ParameterUpdateVisitor : ExpressionVisitor { private ParameterExpression _oldParameter; private ParameterExpression _newParameter; public ParameterUpdateVisitor(ParameterExpression oldParameter, ParameterExpression newParameter) { _oldParameter = oldParameter; _newParameter = newParameter; } protected override Expression VisitParameter(ParameterExpression node) { if (object.ReferenceEquals(node, _oldParameter)) return _newParameter; return base.VisitParameter(node); } } 
+9
source
 System.Linq.Expressions.Expression.And(exp.Body, newExpression.Body); 

exapmle:

 Expression<Func<int, bool>> f = p => true; var a = Expression.And(f.Body, f.Body); ParameterExpression pParam = Expression.Parameter(typeof(int), "p"); var b = (new int[] { 1, 2, 3 }).Where(Expression.Lambda<Func<int, bool>>(a, new ParameterExpression[] { pParam }).Compile()); 
0
source

Source: https://habr.com/ru/post/1382891/


All Articles