Building an expression tree for string.Contains

I am trying to build an expression tree so that I can dynamically filter some data.

I came up with this, but it does not work on the line var lambda =

 foreach (var rule in request.Where.Rules) { var parameterExpression = Expression.Parameter(typeof(string), rule.Field); var left = Expression.Call(parameterExpression, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); var right = Expression.Constant(rule.Data.ToLower()); var method = typeof(string).GetMethod("Contains", new [] { typeof(string) }); var call = Expression.Call(left, method, right); var lambda = Expression.Lambda<Func<T, bool>>(call, parameterExpression); query = query.Where(lambda); } 

Var rule has a field (ex "Name") that I want to compare with the text in rule.Data (ex 'tom'). Therefore, if T.Name.Contains("tom"); , I want the request to include a record, otherwise not.

var query has type IQueryable<T>

EDIT : he finally worked with this code:

 foreach (var rule in request.Where.Rules) { var parameter = Expression.Parameter(typeof(T), "x"); var property = Expression.Property(parameter, rule.Field); var value = Expression.Constant(rule.Data); var type = value.Type; var containsmethod = type.GetMethod("Contains", new[] { typeof(string) }); var call = Expression.Call(property, containsmethod, value); var lambda = Expression.Lambda<Func<T, bool>>(call, parameter); query = query.Where(lambda); } 
+4
source share
2 answers

You are almost there, but your parameter expression must be of type T , not String , you also lack an expression that receives a property from type T as a name.

What you should roughly say is

 val -> Expression.Constant(typeof(string), rule.Field) parameter -> Expression.Parameter(typeof(T), "p") property -> Expression.Property(parameter, "PropertyName") contains -> Expression.Call(property, containsmethod, val) equals true -> Expression.True or equals, something like that 

I release all this, so it may be slightly different from reality. The resulting expression should be something like this

 p => p.Name.Contains(val) 
+2
source

If you want to create a Where query, you must create lambda , then call Where in the query and pass lambda . Try the following:

 Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(call, parameter); MethodCallExpression expression = Expression.Call(typeof(Queryable), "Where", new[] { typeof(T) }, query.Expression, lambda); query = query.Provider.CreateQuery<T>(expression); 

instead

 var result = Expression.IsTrue(call); query = query.Provider.CreateQuery<T>(result); 
0
source

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


All Articles