As part of a WPF application I'm building an expression tree and generating a Predicate to use as a filter. The code looks something like this:
public Expression BuildExpression(Expression parameter, string value)
{
MethodInfo toStringMethod = new Func<Object, string>((a) => a.ToString()).Method;
Expression lhs = Expression.Call(parameter, toStringMethod );
ConstantExpression rhs = Expression.Constant(value);
BinaryExpression result = Expression.Equal(lhs, rhs);
return result;
}
This is because the parameter is an Expression of unknown type - it might be an int, string, Guid or anything else. The problem is that it's difficult to understand what's going on here without copious comments. I'd really like to use a lambda here:
return parameter => parameter.ToString() == value;
The problem is that this doesn't work as intended - the resulting delegate would call ToString() on the Expression instead of the value of the expression. If it helps, parameter is a MemberExpression.
I was able to find a way to do this with very little extra code. The main inspiration for this solution was Mark Gravell's answer to Combining two expressions (Expression<Func<T, bool>>)
Starting from .net 4.0. There is the ExpressionVistor class which allows you to build expressions that are EF safe.
Expression<TDelegate>
is derived from LambdaExpression (if you're interested in learning more about how these actually work I encourage you to check out the "LINQ - Expression Tree Visualizer" sample, currently located at https://code.msdn.microsoft.com/LINQ-Expression-Tree-47608cb5 ). This line of code:
Expression<Predicate<Object>> e1 = a => a.ToString() == "foo";
Creates a LambdaExpression with a single ParameterExpression(Type: Object, ReturnType: Boolean, Body:(LogicalBinaryExpression)). Using a custom ExpressionVisitor we can modify the body of the Lambda to create the same result as my previous code:
public class ReplaceExpressionVisitor
: ExpressionVisitor
{
private readonly Expression _oldValue;
private readonly Expression _newValue;
public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
{
_oldValue = oldValue;
_newValue = newValue;
}
public override Expression Visit(Expression node)
{
if (node == _oldValue)
return _newValue;
return base.Visit(node);
}
}
// Elsewhere...
public Expression BuildExpression(Expression parameter, string value)
{
Expression<Predicate<Object>> e1 = a => a.ToString() == value;
return (new ReplaceExpressionVisitor(e1.Parameters[0], parameter)).Visit(e1.Body);
}
Further cleanup is definitely possible (provide a static and/or extension method) but this meets my needs.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.