Suppose I have something like
Expression<Func<SomeType, DateTime>> left = x => x.SomeDateProperty;
Expression<Func<SomeType, DateTime>> right = x => dateTimeConstant;
var binaryExpression = Expression.GreaterThan(left, right);
Expression<Func<SomeType, bool>> predicate =
x => x.SomeDateProperty> dateTimeConstant;
1) How can I replace the right hand of the assignment of the last line with something that uses the binaryExpression instead? var predicate = x => binaryExpression; doesn't work.
2) The right is always a constant, not necessarily DateTime.Now. Could it be of some simpler Expression type? For instance, it doesn't depend on SomeType, it is just a constant.
3) If I have the GreaterThan as a string, is there a way to get from this string to the method with the same name in Expression? In general, if the name of the comparison method is given as a string, how can I go from the string to actually calling the method with the same name on the Expression class?
It has to work with LINQ to Entities, if it matters.
1 and 2: You need to build the expression tree manually to do this, the compiler cannot help because it only constructs ready-made expressions that represent functions in their entirety. That's not useful when you want to build functions piece by piece.
Here's one straightforward way to build the expression you want:
var argument = Expression.Parameter(typeof(SomeType));
var left = Expression.Property(argument, "SomeDateProperty");
var right = Expression.Constant(DateTime.Now);
var predicate = Expression.Lambda<Func<SomeType, bool>>(
Expression.GreaterThan(left, right),
new[] { argument }
);
You can take this for a test drive with
var param = new SomeType {
SomeDateProperty = DateTime.Now.Add(TimeSpan.FromHours(-1))
};
Console.WriteLine(predicate.Compile()(param)); // "False"
3: Since in all likelihood the number of possible choices for your binary predicate will be quite small, you could do this with a dictionary:
var wordToExpression =
new Dictionary<string, Func<Expression, Expression, BinaryExpression>>
{
{ "GreaterThan", Expression.GreaterThan },
// etc
};
Then, instead of hardcoding Expression.GreaterThan in the first snippet you would do something like wordToExpression["GreaterThan"](left, right).
Of course this can also be done the standard way with reflection.
When you use GreaterThan, you need to specify the expression bodies, not the lambda itself. Unfortunately, there is a complication: the x in the two expressions is not the same.
In this particular case, you could just about get away with this, because the second expression does not use x
So; your "1" and "2" should be answered by:
var binaryExpression = Expression.GreaterThan(left.Body, right.Body);
var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression,
left.Parameters);
However, to handle this in the general case, you must rewrite on of the expressions, to fix-up the parameters:
var binaryExpression = Expression.GreaterThan(left.Body,
new SwapVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body));
var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression,
left.Parameters);
with:
public class SwapVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public SwapVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
For your "3"; there is nothing inbuilt for that; you could use reflection, though:
string method = "GreaterThan";
var op = typeof(Expression).GetMethod(method,
BindingFlags.Public | BindingFlags.Static,
null, new[] { typeof(Expression), typeof(Expression) }, null);
var rightBody = new SwapVisitor(right.Parameters[0],
left.Parameters[0]).Visit(right.Body);
var exp = (Expression)op.Invoke(null, new object[] { left.Body, rightBody });
var lambda = Expression.Lambda<Func<SomeType, bool>>(exp, left.Parameters);
Related
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.
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
I'd like to read the value of some of the properties in the expression tree some I can proceed to some calculations.
var products = db.Products
.Where(GetPredicate())
.ToList();
private Expression<Func<Product, bool>> GetPredicate()
{
ParameterExpression pe = Expression.Parameter(typeof(Product), "p");
Expression exp0 = Expression.Property(pe, "Price");
//I'd like to know the value of the 'Price'
// so I can do some calculation, then check whether
//this particular product meet the criteria...
Expression body = Expression.Constant(Result); //result is a boolean
var expr = Expression.Lambda<Func<Product, bool>>(body, new ParameterExpression[] { pe });
return expr;
}
You seem to be using a database query provider (LINQ2SQL, EF, etc.)
Before you try to use expressions to solve your problem you need to make sure the expression is understood by the query provider. In your case many of the Math methods can be converted to T-SQL valid statements. Also, if you are using Entity Framework you might want to leverage the System.Data.Objects.SqlClient.SqlFunctions class to create an expression and execute your logic on the SQL Server side against native T-SQL functions.
Now, something to understand on expression trees, is that values cannot be obtained from constructing expressions unless this is a LambdaExpression, once compiled you invoke it, in your case you can obtain the bool value.
If you need to work with the price value, you need to create more expressions representing the call to the other logic, in your example the expressions calling the static Sqrt method of the Math class.
private Expression<Func<Product, bool>> GetPredicate()
{
var pe = Expression.Parameter(typeof(Product), "p");
var price = Expression.Property(pe, "Price");
var priceDouble = Expression.Convert(price, typeof(double));
var sqrtMethod = typeof(Math).GetMethod("Sqrt");
var sqrtCall = Expression.Call(sqrtMethod, priceDouble);
var constant = Expression.Constant(4d);
var gtThan = Expression.GreaterThan(sqrtCall, constant);
var lambda = Expression.Lambda<Func<Product, bool>>(gtThan, pe);
return lambda;
}
As you can see all the logic is an expression and the provider can consume the whole expression and convert it to syntax that can be understood by the target process. The prior expression generates p => Math.Sqrt((double)p.Price) > 4d
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()();
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