How do I dynamically create an Expression<Func<MyClass, bool>> predicate? - c#

How would I go about using an Expression Tree to dynamically create a predicate that looks something like...
(p.Length== 5) && (p.SomeOtherProperty == "hello")
So that I can stick the predicate into a lambda expression like so...
q.Where(myDynamicExpression)...
I just need to be pointed in the right direction.
Update: Sorry folks, I left out the fact that I want the predicate to have multiple conditions as above. Sorry for the confusion.

Original
Like so:
var param = Expression.Parameter(typeof(string), "p");
var len = Expression.PropertyOrField(param, "Length");
var body = Expression.Equal(
len, Expression.Constant(5));
var lambda = Expression.Lambda<Func<string, bool>>(
body, param);
Updated
re (p.Length== 5) && (p.SomeOtherProperty == "hello"):
var param = Expression.Parameter(typeof(SomeType), "p");
var body = Expression.AndAlso(
Expression.Equal(
Expression.PropertyOrField(param, "Length"),
Expression.Constant(5)
),
Expression.Equal(
Expression.PropertyOrField(param, "SomeOtherProperty"),
Expression.Constant("hello")
));
var lambda = Expression.Lambda<Func<SomeType, bool>>(body, param);

Use the predicate builder.
http://www.albahari.com/nutshell/predicatebuilder.aspx
Its pretty easy!

To combine several predicates with the && operator, you join them together two at a time.
So if you have a list of Expression objects called predicates, do this:
Expression combined = predicates.Aggregate((l, r) => Expression.AndAlso(l, r));

To associate Lambda expression each other:
An other way is to use the following code. It s more flexible than the Schotime answer in my advice and work perfectly. No external Nuggets needed
Framework 4.0
// Usage first.Compose(second, Expression.And)
public static Expression<T> Compose<T>(this Expression<T> First, Expression<T> Second, Func<Expression, Expression, Expression> Merge)
{
// build parameter map (from parameters of second to parameters of first)
Dictionary<ParameterExpression,ParameterExpression> map = First.Parameters.Select((f, i) => new { f, s = Second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with parameters from the first
Expression secondBody = ParameterRebinder.ReplaceParameters(map, Second.Body);
// apply composition of lambda expression bodies to parameters from the first expression
return Expression.Lambda<T>(Merge(First.Body, secondBody), First.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> First, Expression<Func<T, bool>> Second)
{
return First.Compose(Second, Expression.And);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> First, Expression<Func<T, bool>> second)
{
return First.Compose(second, Expression.Or);
}
public class ParameterRebinder : ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement))
{
p = replacement;
}
return base.VisitParameter(p);
}
}

I have a open-source project called Exprelsior that provides very simple ways to create dynamic predicates:
Based on your example:
var exp1 = ExpressionBuilder.CreateBinary<YourClass>("MyProperty.Length", 5, ExpressionOperator.Equals);
var exp2 = ExpressionBuilder.CreateBinary<YourClass>("SomeOtherProperty", "hello", ExpressionOperator.Equals);
var fullExp = exp1.And(exp2);
// Use it normally...
q.Where(fullExp)
It even supports full text predicate generation, so you can receive any dynamic query from an HTTP GET method, for example:
var exp1 = ExpressionBuilder.CreateBinaryFromQuery<YourClass>("eq('MyProperty.Length', '5')");
var exp2 = ExpressionBuilder.CreateBinaryFromQuery<YourClass>("eq('SomeOtherProperty', 'hello')");
var fullExp = exp1.And(exp2);
// Use it normally...
q.Where(fullExp)
It supports a lot more data types and operators.
Link: https://github.com/alexmurari/Exprelsior

Related

Is it possible to use a C# lambda expression to create an instance of System.Linq.Expressions.Expression at compile time?

A C# lambda expression (of type System.Linq.Expressions.Expression<TDelegate>) in code:
Expression<Func<Something, bool>> predicate = s => s.SomeProperty == 12;
To create a similar instance of System.Linq.Expressions.Expression:
var parameter = Expression.Parameter(typeof(Something), "s");
var property = Expression.Property(parameter, typeof(Something).GetProperty("SomeProperty"));
var constant = Expression.Constant(12);
var expression = Expression.Equal(property, constant);
Is there a way to declare expression given only the predicate? So without building the expression tree step by step in code, but having the compiler infer it from a lambda expression.
var expression = Expression.FromLambda<Something>(s => s.SomeProperty == 12);
Sure, just grab the body of the lambda expression, like so:
Expression FromLambda(Expression<Func<Something, bool>> lambda)
{
return lambda.Body;
}
Then you can use it like so:
var expression = FromLambda(s => s.SomeProperty == 12);
Just return the expression
Expression<Func<T, bool>> FromLambda<T>(Expression<Func<T, bool>> lambda) {
return lambda;
}
And use as desired
var expression = FromLambda<Something>(s => s.SomeProperty == 12);
This however is not very flexible and targets just this scenario. You would need to create methods for any other delegate you want to use.

Func<T, bool> on Any() IEnumerable

i try to query (linq to entities EF Core) a navigation properties collection, so i use any() like this :
var query = context.MyTable.Where(x => x.mycollectionproperties.Any(p => p.myprop == myvar );
It's work perfectly but now i want to construct the predicate and not defined it directly in the query.
so i do :
Func<T, bool> mypredicate = (p => p.myprop == myvar);
var query = context.MyTable.Where(x => x.mycollectionproperties.Any(mypredicate);
(I have replace T by my entity name)
but this generate an error : Object of type 'System.Linq.Expressions.TypedParameterExpression' cannot be converted to type 'System.Linq.Expressions.LambdaExpression'.
How can i construct my predicate to use it on Any() collection ?
Thank's
This line for example:
var query = context.MyTable.Where(x => x.mycollectionproperties.Any(p => p.myprop == 1));
When compiled will be compiled to something like this:
var xParameter = Expression.Parameter(typeof(Entity1), "x");
var pParameter = Expression.Parameter(typeof(Entity2), "p");
var anyMethod =
typeof(Enumerable)
.GetMethods()
.Single(x => x.Name == "Any" && x.GetParameters().Length == 2)
.MakeGenericMethod(typeof(Entity2));
var anyCondition = Expression.Lambda<Func<Entity2, bool>>(
Expression.Equal(
Expression.Property(
pParameter,
typeof(Entity2).GetProperty("myprop").GetMethod),
Expression.Constant(1, typeof(int))),
pParameter);
var query = context.MyTable.Where(
Expression.Lambda<Func<Entity1, bool>>(
Expression.Call(
null,
anyMethod,
new Expression[] {
Expression.Property(
xParameter,
typeof(Entity1).GetProperty("mycollectionproperties").GetMethod),
anyCondition
}),
xParameter));
This is called an expression tree. See this reference for more details:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/
Although the Any method takes a Func, when constructing the expression tree, notice that an expression (Expression<Func<Entity2, bool>>) is given to the Any method.
There doesn't seem to be a way from C# to give the Any method an expression instead of a Func even if the whole thing is an expression tree (I mean in a parameterized way like you want to achieve).
The most obvious way to achieve what you want is to use the code from this post and replace the anyCondition variable with whatever expression you want to use for the condition inside Any.
Another way is to construct part of the expression tree "normally" and pass null to the Any method and then use an expression visitor to replace the null with your expression. Here is how such visitor would look like:
public class AnyMethodArgumentReplacingVisitor : ExpressionVisitor
{
private readonly Expression expression;
public AnyMethodArgumentReplacingVisitor(Expression expression)
{
this.expression = expression;
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.Name == "Any")
{
return Expression.Call(node.Object, node.Method, node.Arguments[0], expression);
}
return base.VisitMethodCall(node);
}
}
Here is how you would use it:
Expression<Func<Entity2, bool>> predicate =
a => a.myprop == 2;
Expression<Func<Entity1, bool>> expression =
b => b.mycollectionproperties.Any(null);
var expression2 =
(Expression<Func<Entity1, bool>>)
new AnyMethodArgumentReplacingVisitor(predicate).Visit(expression);
Please note that such visitor would replace the call to any Any method. It also assumes that only the overload of Any that takes a predicate is used. There is another overload of Any that does not take a predicate. If you need to use that, you need to adjust the code.
It looks to me your problem is in your definition of
Func<T, bool> mypredicate = (p => p.myprop == myvar);
You should not use T, you should use the type of mycollectionproperties
Assuming the property mycollectionproperties is defined as something like this
....
public IQueryable<YourType> mycollectionproperties { get; set; }
....
Then you should declare mypredicate as
Func<YourType, bool> mypredicate = (p => p.myprop == myvar);
You can see a working sample on .NetFiddle

How to use Contains method in Expression Class in C#?

Here is my code as following:
protected Expression<Func<T, bool>> GetLambdaForField(string SearchTxtBox)
{
// Build a Lamda expression to get the Node headers for this sub master.
ConstantExpression constForeignKeyID = Expression.Constant(SearchTxtBox);
ParameterExpression paramEntity =
Expression.Parameter(typeof(T), "e");
MemberExpression mex =
LambdaExpression.PropertyOrField(paramEntity, DefaultSearchFieldName);
BinaryExpression filter = Expression.Equal(mex, constForeignKeyID);
Expression<Func<T, bool>> exprLambda =
Expression.Lambda<Func<T, bool>>(filter,
new ParameterExpression[] { paramEntity });
return exprLambda;
}
I have used Expression.Equal(...); but this is not what I actually wanted to achieve.
I wanted something like the Expression.Contains method (so that it can find the record with partial information without having me to enter the complete value).
You want to use Expression.Call method:
var filter = Expression.Call(mex,
typeof(string).GetMethod("Contains"),
constForeignKeyID);
This is equal to the following expression:
x => x.Prop.Contains(searchString)
Hope this helps.

Creating a linq expression dynamically or parsing the string value of the expression

Got an problem where I need to crate an linq expression dynamically. But I cant seem to wrap my head around it.
So first off I got an check list box. Where I input values from a file that is selected, hence I will not know how many parameters there will be there before I run the code. Then the plan is to construct a linq sentence based on the name of the elements in the checkbox. Let me illustrate:
I want to create an linq statement that looks like this:
var result = from n in data where n.Item1 == "someValueFromCheckBox" select n;
Where the data, is an tupled list like :
List<Tuple<string, string>>
And that is fine as long as the user only selects one item from the checkbox. But when the user for example selects two items, I need to create a linqu expression that looks like this:
var result = from n in data where n.Item1 == "someValueFromCheckBox" || n.Item1 == "someValueFromCheckBox1" select n;
So my first thought was to build the linq statement as a string. In the following manner:
var selectedItems = checkedListBoxSelectedTerms.CheckedItems;
var linqStatement = "";
for (int i = 0; i < selectedItems.Count; i++ )
{
linqStatement += selectedItems[i].ToString() + "|| n.item1 ==" ;
}
//this is simply to remove the || "n.Item1 ==", at the end because it
is not needed after the last selecteditem.
linqStatement = linqStatement.Remove(linqStatement.Length - 13, 13);
But that did not work as planned, because when I put it in like this:
var result = from n in data where n.Item1 == linqStatement select n;
The whole thing becomes a string. And I cant have the "n.Item1 ==" to be a string. In theory that solution would work great for my use, because I would not have to worry about how manay elements that are in the checkbox and how many elements the user selects, but I cannot pass linqStatement whole as a string. So any help would be appriciated, because I cant seem to find an good example to do something like this.
Thanks in advance!
For such a simple example, you should simply have a list or set of strings, and then do Contains. E.g.
var selectedItems = checkedListBoxSelectedTerms.CheckedItems
.Select(x => x.ToString()).ToList();
var result = from n in data where selectedItems.Contains(n.Item1) select n;
If you need more flexible dynamic building capabilities, try something like Dynamic LINQ or PredicateBuilder.
The PredicateBuilder is what I use for dynamic queries.
Please see here for more info:
http://www.albahari.com/nutshell/predicatebuilder.aspx
So what you're looking for is an implementation of a predicate builder that can take any number of expressions and OR them together. Here is an implementation that will work with any query provider:
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0],
expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0],
expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
}
}
which uses:
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
This allows you to take any two expressions and create a new expression that is the result of ORing them together.
List<Tuple<string, string>> list = CreateList();
var finalExpression = list.Aggregate(PredicateBuilder.False<Data>(),
(predicate, pair) => predicate.Or(n => n.Item1 == pair.Item2));
var query = data.Where(finalExpression);

C# negate an expression

I'm seeking for a way to negate an expression used to filter IQueryable sequences.
So, I've got something like:
Expression<Func<T, bool>> expression = (x => true);
Now I wish to create the expression which would result in yielding (x => false) - so I basically want to negate the expression.
The working method I've found myself works like this:
var negatedExpression =
Expression.Lambda<Func<T, bool>> (Expression.Not(expression.Body),
expression.Parameters[0])));
But I'm almost sure there is a better way - could you help me? (something like Not(expression), probably).
An easy extension method:
public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> one)
{
var candidateExpr = one.Parameters[0];
var body = Expression.Not(one.Body);
return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}
Usage:
Expression<Func<int, bool>> condition = x => x > 5;
var source = Enumerable.Range(1, 10);
var result1 = source.Where(condition.Compile()); //6,7,8,9,10
var result2 = source.Where(condition.Not().Compile()); //1,2,3,4,5
Posting for future reference.
Danny Chen's answer can be made more generic:
public static Expression<TFunc> Not<TFunc>(this Expression<TFunc> baseExpr)
{
var param = baseExpr.Parameters;
var body = Expression.Not(baseExpr.Body);
var newExpr = Expression.Lambda<TFunc>(body, param);
return newExpr;
}
This version can receive an Expression with any number of input parameters. It only adds a little useability, however, since the Expression would most likely be passed to a function like IEnumerable.Where anyway.
What about this?
Expression<Func<bool>> expr = () => true;
Expression<Func<bool>> negated = () => !expr.Compile()();

Categories

Resources