I'm trying to modify the expression of a function.
I want to replace a functions input argument with a function that returns the same value.
The idea is to convert: function (Foo foo) { return foo.ToString(); }
with function(Func<Foo> fooProvider) { return fooProvider().ToString() }
Actually I don't even want to call the function passed to us, but directly use the body of the function.
So the real example does not get an Func<Foo> as input, but an Expression<Func<Foo>>.
Example code can be found below.
I assume I get an exception now because I change the signature of the function.
Although that is exactly what I want to do.
Some code:
The program
class Program
{
public static void Run()
{
Expression<Func<int, bool>> isOdd = number => (number % 2) == 1;
Expression<Func<string, int>> parseTextToNumber = text => Convert.ToInt32(text);
var vistor = new ReplaceExpressionVisitor(isOdd.Parameters[0], parseTextToNumber.Body);
var result = vistor.Visit(isOdd);
Expression<Func<string, bool>> textRepresentsOddNumber = result as dynamic;
//Expected something like this:
Expression<Func<string, bool>> expectedResult = text => (Convert.ToInt32(text) % 2) == 1;
}
}
The visitor class
private 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);
}
}
And the error message:
System.InvalidOperationException: 'When called from 'VisitLambda', rewriting a node of type 'System.Linq.Expressions.ParameterExpression'
must return a non - null value of the same type.
Alternatively, override 'VisitLambda' and change it to not visit children of this type.'
After a couple of hours I did found something that works.
PS: Not sure if it is the most generic or best solution there is to this problem.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
public class Program
{
public static void Run()
{
Expression<Func<int, bool>> isOdd = number => (number % 2) == 0;
Expression<Func<string, int>> parseTextToNumber = text => Convert.ToInt32(text);
var visitor = new ReplaceExpressionVisitor(isOdd.Parameters[0], parseTextToNumber.Body);
var result = Expression.Lambda(visitor.Visit(isOdd.Body), parseTextToNumber.Parameters);
Expression<Func<string, bool>> textRepresentsOddNumber = result as dynamic;
//test:
var code = textRepresentsOddNumber.Compile();
Console.WriteLine(code.DynamicInvoke("0"));//writes false
Console.WriteLine(code.DynamicInvoke("1"));//writes true
}
}
private 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);
}
}
Related
I have the following problem in my lambda expression: I need to rename the property because it will be passed from entity to entity. In other words: I need to use the same expression in more than one query in different entities.
For example:
var expr = x => x.Id == converterId
To be
var expr = x => x.ConverterId == converterId
I have tried to do the following
var oldParam = expr.Parameters[0];
var newParam = Expression.Parameter(oldParam.Type, "ConverterId");
This code replaces x not Id`
This isn't trivial, but can be done my writing (subclassing) an ExpressionVisitor, and overriding VisitMember, making the substitution for a different Expression.Property, but using the original target expression (from the expression in the original lambda)
However, for simple cases, it is probably easier to forget that, and just build the expression-tree manually from first principles, rather than using a lambda.
The following shows both approaches:
using System;
using System.Linq.Expressions;
static class P
{
static void Main()
{
// the compiler-generated expression-tree from the question
Console.WriteLine(Baseline(42));
// build our own epression trees manually
Console.WriteLine(ByName(42, nameof(Foo.Id)));
Console.WriteLine(ByName(42, nameof(Foo.ConverterId)));
// take the compiler-generated expression tree, and rewrite it with a visitor
Console.WriteLine(Convert(Baseline(42), nameof(Foo.Id), nameof(Foo.ConverterId)));
}
static Expression<Func<Foo, bool>> Baseline(int converterId)
{
// note this uses a "captured variable", so the output
// looks uglier than you might expect
return x => x.Id == converterId;
}
static Expression<Func<Foo, bool>> ByName(int converterId, string propertyOrFieldName)
{
var p = Expression.Parameter(typeof(Foo), "x");
var body = Expression.Equal(
Expression.PropertyOrField(p, propertyOrFieldName),
Expression.Constant(converterId, typeof(int))
);
return Expression.Lambda<Func<Foo, bool>>(body, p);
}
static Expression<Func<Foo, bool>> Convert(
Expression<Func<Foo, bool>> lambda, string from, string to)
{
var visitor = new ConversionVisitor(from, to);
return (Expression<Func<Foo, bool>>)visitor.Visit(lambda);
}
class ConversionVisitor : ExpressionVisitor
{
private readonly string _from, _to;
public ConversionVisitor(string from, string to)
{
_from = from;
_to = to;
}
protected override Expression VisitMember(MemberExpression node)
{
if(node.Member.Name == _from)
{
return Expression.PropertyOrField(
node.Expression, _to);
}
return base.VisitMember(node);
}
}
}
class Foo
{
public int Id { get; set; }
public int ConverterId { get; set; }
}
Is it possible to dynamically rewrite an Expression<T>, replacing an element of T with another type?
For example, replacing the DocumentTypeA with DocumentTypeB in the following situations:
Expression<Func<DocumentTypeA, bool>> expression = m => m.Details.Id == "an-id"
Expression<Func<DocumentTypeA, bool>> expression = m => m.Details.Id == "an-id" && m.AnInt == 42
Expression<Func<DocumentTypeA, bool>> expression = m => m.AString == "I'm a string"
I'll need to make the decision about what type to use at runtime, rather than compile time.
It's also worth noting that DocumentTypeA and DocumentTypeB don't relate to each other, apart from their properties are identical.
The end result would be to reprocess them so they now look like
Expression<Func<DocumentTypeB, bool>> expression = m => m.Details.Id == "an-id"
Expression<Func<DocumentTypeB, bool>> expression = m => m.Details.Id == "an-id" && m.AnInt == 42
Expression<Func<DocumentTypeB, bool>> expression = m => m.AString == "I'm a string"
So the actual comparison part of the expression remains unchanged, only the top-level type has changed.
You can use ExpressionVisitor to replace the type.
class ParameterRewriter<T, U> : ExpressionVisitor
{
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type.Equals(typeof(T)))
{
return Expression.Parameter(typeof(U), node.Name);
}
return base.VisitParameter(node);
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression is ParameterExpression paramExp && paramExp.Type.Equals(typeof(T)))
{
return Expression.MakeMemberAccess(
Expression.Parameter(typeof(U), paramExp.Name),
typeof(U).GetMember(node.Member.Name).Single());
}
return base.VisitMember(node);
}
protected override Expression VisitLambda<L>(Expression<L> node)
{
var parameters = node.Parameters.ToList();
var found = false;
for (var i = 0; i < parameters.Count; i++)
{
if (parameters[i].Type.Equals(typeof(T)))
{
parameters[i] = Expression.Parameter(typeof(U), parameters[i].Name);
found = true;
}
}
if (found)
{
return Expression.Lambda(node.Body, parameters);
}
return base.VisitLambda(node);
}
}
In this case, create an instance new ParameterRewriter<DocumentTypeA, DocumentTypeB>() and visit the original expression tree, you will get what you want. An extension method maybe more readable:
public static class ExpressionExtensions
{
public static Expression<Func<U, R>> RewriteParameter<T, U, R>(this Expression<Func<T, R>> expression)
{
var rewriter = new ParameterRewriter<T, U>();
return (Expression<Func<U, R>>)rewriter.Visit(expression);
}
}
The usage is simple:
Expression<Func<A, bool>> expA = x => x.Id == 1;
Expression<Func<B, bool>> expB = expA.RewriteParameter<A, B, bool>();
Use an interface that both classes inherit from and contains the properties that are identical in both of the classes e.g.
interface IDocumentTypes
{
string AString { get; set; } //indicates that both classes need to implement this
//etc...
}
class DocumentTypeA : IDocumentTypes
{
//your class
}
Then both of your classes can use the Expression when it implements the interface IDocumentTypes and still be strongly typed. The classes don't need to have anything in common other than implementing the properties/functions defined in the interface.
I am trying to use expression trees so that I can choose to map across to a DTO using entity framework in much the same way as the Include directive works on a DbSet (part of an open sorce project implementing OData).
The code below represents a test case.
Expression<Func<Bar, Bar>> mapBar = b => new Bar { BarInt = b.BarInt, BarString = b.BarString };
Expression<Func<Foo, Foo>> mapFoo = f => new Foo { FooInt = f.FooInt, B = null };
Expression<Func<Foo, Foo>> target = f => new Foo { FooInt = f.FooInt,
B = new Bar {
BarInt=f.B.BarInt, BarString = f.B.BarString
} };
note Foo.B was null, and has the mapBar expression inserted.
I have got as far as adding the navigation property using the following ExpressionVisitor
public class UpdateExpressionVisitor : ExpressionVisitor
{
private readonly ParameterExpression _oldExpr;
private readonly Expression _newExpr;
public UpdateExpressionVisitor(ParameterExpression oldExpr, Expression newExpr)
{
_oldExpr = oldExpr;
_newExpr = newExpr;
}
protected override MemberAssignment VisitMemberAssignment(MemberAssignment node)
{
if (node.Member.Name == _oldExpr.Name)
{
return node.Update(_newExpr);
}
Console.WriteLine(node);
return base.VisitMemberAssignment(node);
}
}
But I cant figure out how to alter the expression new Bar { BarInt = b.BarInt,..., to become new Bar { BarInt = f.B.BarInt,...
The function will need some kind of ExpressionVisitor like so
public class MergingVisitor : ExpressionVisitor
{
private readonly ParameterExpression _oldExpr;
private readonly ParameterExpression _newProp;
private readonly ParameterExpression _newParent;
public MergingVisitor(ParameterExpression oldExpr, ParameterExpression newProp, ParameterExpression newParent)
{
_oldExpr = oldExpr;
_newProp = newProp;
_newParent = newParent;
}
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression == _oldExpr)
{
/*!!what to do here!!*/
var ma = Expression.MakeMemberAccess(_newProp, node.Member);
return Expression.MakeMemberAccess(_newParent, ma.Member);
}
return base.VisitMember(node);
}
and they all need to be linked together with something like
public static Expression<Func<T, TMap>> MapNavProperty<T, TMap, U, UMap>(this Expression<Func<T, TMap>> parent, Expression<Func<U, UMap>> nav, string propName)
{
//concern 1 remap name of prop in nav - not sure if I should do this first
var parentInitVarName = parent.Parameters[0].Name;
var parentParam = Expression.Parameter(typeof(T), parentInitVarName);
var propParam = Expression.Parameter(typeof(U), propName);
var mergeVisitor = new MergingVisitor(nav.Parameters[0], propParam, parentParam);
var newNavBody = mergeVisitor.Visit(nav.Body); //as MemberExpression;
//concern 2 replace given property
var visitor = new UpdateExpressionVisitor(propParam, nav.Body);
return (Expression<Func<T, TMap>>)visitor.Visit(parent);
}
although at present the parentParam will fail in the Expression.MakeMemberAccess function as it is of type T (Foo in the above example), rather than type U.
How can I alter the variable name and types in the child property's lamda expression - thank you.
Update
The answers from Svick and Ivan Stoev are erudite in explanation and both work perfectly - the (passing) unit tests and code from both answers are up on GitHub here. Thank you so much to both of you - it is a shame I cannot tick 2 answers, so it comes down to Eeny, meeny, miny, moe.
var parentParam = Expression.Parameter(typeof(T), parentInitVarName);
This won't work, parameters in expressions are not identified by name, but by reference. What you need to do is just get the parent's parameter.
var propParam = Expression.Parameter(typeof(U), propName);
This doesn't make any sense to me. propName is the name of a property, so you need to use it to create member access expression, not parameter expression.
public MergingVisitor(ParameterExpression oldExpr, ParameterExpression newProp, ParameterExpression newParent)
What you need is to replace one expression (b) with another (f.B). For that, I would create:
public class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression _oldExpr;
private readonly Expression _newExpr;
public ReplaceVisitor(Expression oldExpr, Expression newExpr)
{
_oldExpr = oldExpr;
_newExpr = newExpr;
}
public override Expression Visit(Expression node)
{
if (node == _oldExpr)
{
return _newExpr;
}
return base.Visit(node);
}
}
public UpdateExpressionVisitor(ParameterExpression oldExpr, Expression newExpr)
It doesn't make any sense for oldExpr to be a parameter expression. What you need is just a string.
var visitor = new UpdateExpressionVisitor(propParam, nav.Body);
You need to actually use newNavBody here.
The whole MapNavProperty() will now look like this:
var parentParam = parent.Parameters.Single();
var propExpression = Expression.Property(parentParam, propName);
var mergeVisitor = new ReplaceVisitor(nav.Parameters.Single(), propExpression);
var newNavBody = mergeVisitor.Visit(nav.Body);
var visitor = new UpdateExpressionVisitor(propName, newNavBody);
return (Expression<Func<T, TMap>>)visitor.Visit(parent);
With these changes, your code will work.
I would personally use different helpers:
(1) For replacing parameter
static Expression ReplaceParameter(this LambdaExpression lambda, Expression target)
{
return lambda.Body.ReplaceParameter(lambda.Parameters.Single(), target);
}
static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
{
return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
}
class ParameterReplacer : ExpressionVisitor
{
public ParameterExpression Source;
public Expression Target;
protected override Expression VisitParameter(ParameterExpression node)
{
return node == Source ? Target : base.VisitParameter(node);
}
}
(2) For replacing member assignment value
static Expression ReplaceMemberAssignment(this Expression expression, MemberInfo member, Expression value)
{
return new MemberAssignmentReplacer { Member = member, Value = value }.Visit(expression);
}
class MemberAssignmentReplacer : ExpressionVisitor
{
public MemberInfo Member;
public Expression Value;
protected override MemberAssignment VisitMemberAssignment(MemberAssignment node)
{
return node.Member == Member ? node.Update(Value) : base.VisitMemberAssignment(node);
}
}
With these helpers, the function in question would be something like this:
public static Expression<Func<T, TMap>> MapNavProperty<T, TMap, U, UMap>(this Expression<Func<T, TMap>> parent, Expression<Func<U, UMap>> nav, string propName)
{
var parameter = parent.Parameters[0];
var body = parent.Body.ReplaceMemberAssignment(
typeof(TMap).GetProperty(propName),
nav.ReplaceParameter(Expression.Property(parameter, propName))
);
return Expression.Lambda<Func<T, TMap>>(body, parameter);
}
I have an expression like: Expression<Func<TheObject, int, bool>> myExpression = (myObj, theType) => { myObj.Prop > theType };
I need to dynamically rebuild myExpression to a new expression of type Expression<Func<TheObject, bool>> and replace “theType” parameter from the first expression with a concrete value 123 like:
Expression<Func<TheObject, bool>> myNewExpression = myObj => { myObj.Prop > 123 };
How can I do that?
Br
Philip
With a simple expression replacer it is quite easy:
This is the one I've written for myself... supports simple replaces and multiple replaces.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
// A simple expression visitor to replace some nodes of an expression
// with some other nodes. Can be used with anything, not only with
// ParameterExpression
public class SimpleExpressionReplacer : ExpressionVisitor
{
public readonly Dictionary<Expression, Expression> Replaces;
public SimpleExpressionReplacer(Expression from, Expression to)
{
Replaces = new Dictionary<Expression, Expression> { { from, to } };
}
public SimpleExpressionReplacer(Dictionary<Expression, Expression> replaces)
{
// Note that we should really clone from and to... But we will
// ignore this!
Replaces = replaces;
}
public SimpleExpressionReplacer(IEnumerable<Expression> from, IEnumerable<Expression> to)
{
Replaces = new Dictionary<Expression, Expression>();
using (var enu1 = from.GetEnumerator())
using (var enu2 = to.GetEnumerator())
{
while (true)
{
bool res1 = enu1.MoveNext();
bool res2 = enu2.MoveNext();
if (!res1 || !res2)
{
if (!res1 && !res2)
{
break;
}
if (!res1)
{
throw new ArgumentException("from shorter");
}
throw new ArgumentException("to shorter");
}
Replaces.Add(enu1.Current, enu2.Current);
}
}
}
public override Expression Visit(Expression node)
{
Expression to;
if (node != null && Replaces.TryGetValue(node, out to))
{
return base.Visit(to);
}
return base.Visit(node);
}
}
Your TheObject
public class TheObject
{
public int Prop { get; set; }
}
Then you only need to replace the 2nd parameter in the body of the expression and rebuild the Expression<>
public class Program
{
public static void Main(string[] args)
{
Expression<Func<TheObject, int, bool>> myExpression = (myObj, theType) => myObj.Prop > theType;
int value = 123;
var body = myExpression.Body;
var body2 = new SimpleExpressionReplacer(myExpression.Parameters[1], Expression.Constant(value)).Visit(body);
Expression<Func<TheObject, bool>> myExpression2 = Expression.Lambda<Func<TheObject, bool>>(body2, myExpression.Parameters[0]);
}
}
public IEnumerable<Table1> GetMatchingTable1(string param, double[] Thicknesses)
{
return DBContext.Table1.Where(c => c.Field1 == param
&& Thicknesses.Any(Thickness => Thickness >= c.MinThickness && Thickness <= c.MaxThickness))
.ToList();
}
Above query return the following exception. "Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries."
So far, all my research on the web for this error pointed toward replacing "ANY" with "CONTAINS". Here is one site where they fix the problem using this solution : http://blog.hompus.nl/2010/08/26/joining-an-iqueryable-with-an-ienumerable/
But in my case, "CONTAINS" doesn't seem usable since I check a RANGE with Min and Max.
How should this query be written to have a proper SQL Statement generated by LinqToEntity?
Thanks
You could try to build the query dynamically:
public IEnumerable<Table1> GetAllCoilLengthSettingsWithChilds(string param, double[] Thicknesses)
{
// Base query
var query = LinqKit.Extensions.AsExpandable(DBContext.Table1.Where(c => c.Field1 == param));
// All the various || between the Thickness ranges
var predicate = LinqKit.PredicateBuilder.False<Table1>();
foreach (double th in Thicknesses)
{
// Don't want a closure around th
double th2 = th;
predicate = predicate.Or(c => th2 >= c.MinThickness && th2 <= c.MaxThickness);
}
// This is implicitly in && with the other Where
query = query.Where(predicate);
return query.ToList();
}
The PredicateBuilder helps you build an || query. Take it from the LinqKit (source available)
I've tested it with 1000 parameters (but they where DateTime, and I didn't have other query pieces), and it seems to work. Note that the program uses another extension of LinqPad, AsExpandable, used to make the PredicateBuilder "trick" work. Note that I'm using EF 6.1.3, so your mileage may vary.
If you don't want to use LinqKit, I'm appending my version of PredicateBuilder. It doesn't require the use of AsExpandable(), but its syntax is slightly different:
public class PredicateBuilder<T>
{
// We share a single parameter for all the PredicatBuilder<T>
// istances. This isn't a proble, because Expressions are immutable
protected static readonly ParameterExpression Parameter = Expression.Parameter(typeof(T), "x");
protected Expression Current { get; set; }
// Returns an empty PredicateBuilder that, if used, is true
public PredicateBuilder()
{
}
// Use it like this: .Where(predicate) or .Any(predicate) or
// .First(predicate) or...
public static implicit operator Expression<Func<T, bool>>(PredicateBuilder<T> predicate)
{
if (object.ReferenceEquals(predicate, null))
{
return null;
}
// Handling of empty PredicateBuilder
Expression current = predicate.Current ?? Expression.Constant(true);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(current, Parameter);
return lambda;
}
public static implicit operator PredicateBuilder<T>(Expression<Func<T, bool>> expression)
{
var predicate = new PredicateBuilder<T>();
if (expression != null)
{
// Equivalent to predicate.Or(expression)
predicate.And(expression);
}
return predicate;
}
public void And(Expression<Func<T, bool>> expression)
{
if (expression == null)
{
throw new ArgumentNullException("expression");
}
var expression2 = new ParameterConverter(expression.Parameters[0], Parameter).Visit(expression.Body);
this.Current = this.Current != null ? Expression.AndAlso(this.Current, expression2) : expression2;
}
public void Or(Expression<Func<T, bool>> expression)
{
if (expression == null)
{
throw new ArgumentNullException("expression");
}
var expression2 = new ParameterConverter(expression.Parameters[0], Parameter).Visit(expression.Body);
this.Current = this.Current != null ? Expression.OrElse(this.Current, expression2) : expression2;
}
public override string ToString()
{
// We reuse the .ToString() of Expression<Func<T, bool>>
// Implicit cast here :-)
Expression<Func<T, bool>> expression = this;
return expression.ToString();
}
// Small ExpressionVisitor that replaces the ParameterExpression of
// an Expression with another ParameterExpression (to make two
// Expressions "compatible")
protected class ParameterConverter : ExpressionVisitor
{
public readonly ParameterExpression From;
public readonly ParameterExpression To;
public ParameterConverter(ParameterExpression from, ParameterExpression to)
{
this.From = from;
this.To = to;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == this.From)
{
node = this.To;
}
return base.VisitParameter(node);
}
}
}
public static class PredicateBuilder
{
// The value of source isn't really necessary/interesting. Its type
// is :-) By passing a query you are building to Create, the compiler
// will give to Create the the of the object returned from the query
// Use it like:
// var predicate = PredicateBuilder.Create<MyType>();
// or
// var predicate = PredicateBuilder.Create(query);
public static PredicateBuilder<T> Create<T>(IEnumerable<T> source = null)
{
return new PredicateBuilder<T>();
}
// Useful if you want to start with a query:
// var predicate = PredicateBuilder.Create<MyType>(x => x.ID != 0);
// Note that if expression == null, then a new PredicateBuilder<T>()
// will be returned (that by default is "true")
public static PredicateBuilder<T> Create<T>(Expression<Func<T, bool>> expression)
{
// Implicit cast to PredicateBuilder<T>
return expression;
}
}
Use it like:
var predicate = PredicateBuilder.Create(query);
and then everything is the same (but remove the LinqKit.Extensions.AsExpandable part)