I need to concatenate two expressions (with or statement)
My code:
var items = new List<Item>
{
new Item { Color = "Black", Categories = new List<string> { "cat1", "cat2" } },
new Item { Color = "Red", Categories = new List<string> { "cat3" } },
new Item { Color = "White", Categories = new List<string> { "cat1" } }
};
var categories = new List<string> { "cat2", "cat3" };
Expression<Func<Item, bool>> func1 = (x1) => x1.Color == "Black";
Expression<Func<Item, bool>> func2 = (x2) => x2.Categories.Any(y => categories.Where(z => z == y).Any());
Expression<Func<Item, bool>> fullExpression = Expression.Lambda<Func<Item, bool>>(
Expression.Or(func1.Body, func2.Body), func1.Parameters.Single());
var result = items.AsQueryable().Where(fullExpression);
// result should be like this
// items.Where(x => (x.Color == "Black") || x.Categories.Any(y => categories.Where(z => z == y).Any()))
I get run-time error variable 'x2' of type 'Item' referenced from scope '', but it is not defined'
I also was trying to build an expression with ExpressionVisitor.
Here is ExpressionVisitor:
internal class ParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
internal ParameterReplacer(ParameterExpression parameter)
{
_parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return base.VisitParameter(_parameter);
}
}
Here how I use it in code:
Expression<Func<Item, bool>> func1 = (x1) => x1.Color == "Black";
Expression<Func<Item, bool>> func2 = (x2) => x2.Categories.Any(y => categories.Select(z => z == y).Any());
var paramExpr = Expression.Parameter(typeof(Item));
var exprBody = Expression.Or(func1.Body, func2.Body);
exprBody = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody);
var finalExpr = Expression.Lambda<Func<Item, bool>>(exprBody, paramExpr);
var result = items.AsQueryable().Where(finalExpr);
In this case during creating ParameterReplacer I'm getting error
System.InvalidOperationException: 'The operands for operator 'Equal' do not match the parameters of method 'op_Equality'.'
What did I do wrong?
Ian Newson is entirely right but if you want code, here you go :)
Using these two classes you can combine the two predicates. I didn't come up with it but improved/adjusted it a bit and made it use the type Predicate instead of Func along with some newer language features (the original was quite old, sadly I don't remember where I found it).
internal class SubstExpressionVisitor : ExpressionVisitor
{
private readonly Dictionary<Expression, Expression> _subst = new Dictionary<Expression, Expression>();
protected override Expression VisitParameter(ParameterExpression node)
{
if (_subst.TryGetValue(node, out Expression newValue))
{
return newValue;
}
return node;
}
public Expression this[Expression original]
{
get => _subst[original];
set => _subst[original] = value;
}
}
public static class PredicateBuilder
{
// you don't seem to need this but it's included for completeness sake
public static Expression<Predicate<T>> And<T>(this Expression<Predicate<T>> a, Expression<Predicate<T>> b)
{
if (a == null)
throw new ArgumentNullException(nameof(a));
if (b == null)
throw new ArgumentNullException(nameof(b));
ParameterExpression p = a.Parameters[0];
SubstExpressionVisitor visitor = new SubstExpressionVisitor();
visitor[b.Parameters[0]] = p;
Expression body = Expression.AndAlso(a.Body, visitor.Visit(b.Body));
return Expression.Lambda<Predicate<T>>(body, p);
}
public static Expression<Predicate<T>> Or<T>(this Expression<Predicate<T>> a, Expression<Predicate<T>> b)
{
if (a == null)
throw new ArgumentNullException(nameof(a));
if (b == null)
throw new ArgumentNullException(nameof(b));
ParameterExpression p = a.Parameters[0];
SubstExpressionVisitor visitor = new SubstExpressionVisitor();
visitor[b.Parameters[0]] = p;
Expression body = Expression.OrElse(a.Body, visitor.Visit(b.Body));
return Expression.Lambda<Predicate<T>>(body, p);
}
}
You can use it like this:
Expression<Predicate<Item>> func1 = (x1) => x1.Color == "Black";
Expression<Predicate<Item>> func2 = (x2) => x2.Categories.Any(y => categories.Select(z => z == y).Any());
Expression<Predicate<Item>> finalExpr = func1.Or(func2);
You might want to keep in mind that my Or is using OrElse internally so the second expression won't be evaluated if the one before is evaluated to true (OrElse is like ||, not |). The same goes for And with AndAlso (AndAlso is like &&, not &).
Another thing to note is that you can easily replace Predicate<T> with Func<T, bool> if you have to use Func for some reason :)
This is because your two expressions (func1 and func2) reference two different ParameterExpressions. Just because they're of the same type doesn't mean they're the same.
They need to be the exact same ParameterExpression instance for this to work. For that you can leverage an expression rewriter to modify one of the expressions: https://learn.microsoft.com/en-us/dotnet/api/system.linq.expressions.expressionvisitor?view=netframework-4.8
I think you should be able to use a library like predicate builder to do the same thing in a simpler way though:
https://www.nuget.org/packages/PredicateBuilder/
EDIT:
Your code is on the right lines, but make the following changes:
For the visitor:
internal class ParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
internal ParameterReplacer(ParameterExpression parameter)
{
_parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node;
}
}
For the execution bit:
Expression<Func<Item, bool>> func1 = (x1) => x1.Color == "Black";
Expression<Func<Item, bool>> func2 = (x2) => x2.Categories.Any(y => categories.Select(z => z == y).Any());
var paramExpr = func1.Parameters.Single();
var expr2 = new ParameterReplacer(paramExpr).Visit(func1);
var exprBody = Expression.Or(func1.Body, ((LambdaExpression)expr2).Body);
var finalExpr = Expression.Lambda<Func<Item, bool>>(exprBody, paramExpr);
var result = items.AsQueryable().Where(finalExpr)
.ToList();
Say I have this expression:
int setsize = 20;
Expression<Func<Foo, bool>> predicate = x => x.Seed % setsize == 1
|| x.Seed % setsize == 4;
This basically 'partitions' a set of elements into 20 partitions and retrieves from each set each first and fourth element.
This expression is passed to MongoDB which it's driver is perfectly capable of translating into a MongoDB "query". The predicate can, however, also be used on a list of objects (LINQ2Objects) etc. I want this expression to be reusable (DRY). However, I want to be able to pass in an IEnumerable<int> to specify which items to retrieve (so 1 and 4 aren't "hardcoded" into it):
public Expression<Func<Foo, bool>> GetPredicate(IEnumerable<int> items) {
//Build expression here and return it
}
With LINQPad using this code:
int setsize = 20;
Expression<Func<Foo, bool>> predicate = x => x.Seed % setsize == 1 || x.Seed % setsize == 4;
predicate.Dump();
}
class Foo
{
public int Seed { get; set; }
I can examine the expression:
Now, I want to be able to build an exact reproduction of this expression but with a variable amount of integers to pass (so instead of 1 and 4 I could pass, for example, [1, 5, 9, 11] or [8] or [1, 2, 3, 4, 5, 6, ..., 16]).
I have tried using BinaryExpressions etc. but haven't been able to construct this message correctly. The main issue is that most of my attempts will fail when passing the predicate to MongoDB. The "hardcoded" version works fine but somehow all my attempts to pass my dynamic expressions fail to be translated into a MongoDB query by the C# driver:
{
"$or" : [{
"Seed" : { "$mod" : [20, 1] }
}, {
"Seed" : { "$mod" : [20, 4] }
}]
}
Basically, I want to dynamically build the expression at runtime in such a way that it exactly replicates what the compiler generates for the 'hardcoded' version.
Any help will be appreciated.
EDIT
As requested in the comments (and posted on pastebin), one of my tries below. I'm posting it in the question for furure reference should pastebin take it down or stop their serivce or...
using MongoRepository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
class Program
{
static void Main(string[] args)
{
MongoRepository<Foo> repo = new MongoRepository<Foo>();
var reporesult = repo.All().Where(IsInSet(new[] { 1, 4 }, 20)).ToArray();
}
private static Expression<Func<Foo, bool>> IsInSet(IEnumerable<int> seeds, int setsize)
{
if (seeds == null)
throw new ArgumentNullException("s");
if (!seeds.Any())
throw new ArgumentException("No sets specified");
return seeds.Select<int, Expression<Func<Foo, bool>>>(seed => x => x.Seed % setsize == seed).JoinByOr();
}
}
public class Foo : Entity
{
public int Seed { get; set; }
}
public static class Extensions
{
public static Expression<Func<T, bool>> JoinByOr<T>(this IEnumerable<Expression<Func<T, bool>>> filters)
{
var firstFilter = filters.First();
var body = firstFilter.Body;
var param = firstFilter.Parameters.ToArray();
foreach (var nextFilter in filters.Skip(1))
{
var nextBody = Expression.Invoke(nextFilter, param);
body = Expression.Or(body, nextBody);
}
return Expression.Lambda<Func<T, bool>>(body, param);
}
}
This results in: Unsupported where clause: <InvocationExpression>.
Try this:
public Expression<Func<Foo, bool>> GetExpression<T>(
int setSize, int[] elements,
Expression<Func<Foo, T>> property)
{
var seedProperty = GetPropertyInfo(property);
var parameter = Expression.Parameter(typeof(Foo));
Expression body = null;
foreach(var element in elements)
{
var condition = GetCondition(parameter, seedProperty, setSize, element);
if(body == null)
body = condition;
else
body = Expression.OrElse(body, condition);
}
if(body == null)
body = Expression.Constant(false);
return Expression.Lambda<Func<Foo, bool>>(body, parameter);
}
public Expression GetCondition(
ParameterExpression parameter, PropertyInfo seedProperty,
int setSize, int element)
{
return Expression.Equal(
Expression.Modulo(Expression.Property(parameter, seedProperty),
Expression.Constant(setSize)),
Expression.Constant(element));
}
public static PropertyInfo GetPropertyInfo(LambdaExpression propertyExpression)
{
if (propertyExpression == null)
throw new ArgumentNullException("propertyExpression");
var body = propertyExpression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException(
string.Format(
"'propertyExpression' should be a member expression, "
+ "but it is a {0}", propertyExpression.Body.GetType()));
}
var propertyInfo = body.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException(
string.Format(
"The member used in the expression should be a property, "
+ "but it is a {0}", body.Member.GetType()));
}
return propertyInfo;
}
You would call it like this:
GetExpression(setSize, elements, x => x.Seed);
If you want it to be generic in Foo also, you need change it like this:
public static Expression<Func<TEntity, bool>> GetExpression<TEntity, TProperty>(
int setSize, int[] elements,
Expression<Func<TEntity, TProperty>> property)
{
var propertyInfo = GetPropertyInfo(property);
var parameter = Expression.Parameter(typeof(TEntity));
Expression body = null;
foreach(var element in elements)
{
var condition = GetCondition(parameter, propertyInfo , setSize, element);
if(body == null)
body = condition;
else
body = Expression.OrElse(body, condition);
}
if(body == null)
body = Expression.Constant(false);
return Expression.Lambda<Func<TEntity, bool>>(body, parameter);
}
Now, the call would look like this:
GetExpression(setSize, elements, (Foo x) => x.Seed);
In this scenario it is important to specify the type of x explicitly, otherwise type-inference won't work and you would have to specify both Foo and the type of the property as generic arguments to GetExpression.
basically I want to get the values of the parameters of a called method like this:
var x = 1;
var a = 2;
var b = 3;
Do<HomeController>(o => o.Save(x, "Jimmy", a+b+5, Math.Sqrt(81)));
public static void Do<T>(Expression<Action<T>> expression) where T : Controller
{
// get the values 1,Jimmy,10,9 here
}
Well, you'd need to drill into the expression, find the MethodCallExpression, and then look at the arguments to it. Note that we don't have the value of o, so we've got to assume that the arguments to the method don't rely on that. Also we're still assuming that the lambda expression just relies on it being a MethodCallExpression?
EDIT: Okay, here's an edited version which evaluates the arguments. However, it assumes you're not really using the lambda expression parameter within the arguments (which is what the new object[1] is about - it's providing a null parameter, effectively).
using System;
using System.Linq.Expressions;
class Foo
{
public void Save(int x, string y, int z, double d)
{
}
}
class Program
{
static void Main()
{
var x = 1;
var a = 2;
var b = 3;
ShowValues<Foo>(o => o.Save(x, "Jimmy", a + b + 5, Math.Sqrt(81)));
}
static void ShowValues<T>(Expression<Action<T>> expression)
{
var call = expression.Body as MethodCallExpression;
if (call == null)
{
throw new ArgumentException("Not a method call");
}
foreach (Expression argument in call.Arguments)
{
LambdaExpression lambda = Expression.Lambda(argument,
expression.Parameters);
Delegate d = lambda.Compile();
object value = d.DynamicInvoke(new object[1]);
Console.WriteLine("Got value: {0}", value);
}
}
}
As Jon said you can check to see if the expression is a MethodCallExpression
class Program
{
static void Main(string[] args)
{
Program.Do<Controller>(c => c.Save(1, "Jimmy"));
}
public static void Do<T>(Expression<Action<T>> expression) where T : Controller
{
var body = expression.Body as MethodCallExpression;
if (body != null)
{
foreach (var argument in body.Arguments)
{
var constant = argument as ConstantExpression;
if (constant != null)
{
Console.WriteLine(constant.Value);
}
}
}
}
}
public class Controller
{
public void Save(int id, string name)
{
}
}
My universal answer is below. I hope it will help you and somebody else.
var dict = new Dictionary<string, object>();
var parameterExpressions = methodCallExpr.Arguments;
foreach (var param in method.GetParameters())
{
var parameterExpression = parameterExpressions[counter];
var paramValueAccessor = Expression.Lambda(parameterExpression);
var paramValue = paramValueAccessor.Compile().DynamicInvoke();
dict[param.Name] = paramValue;
}
Here is some code that is designed to work with any expression — in the sense that it doesn’t fundamentally assume that you are passing in a method-call expression. However, it is not complete. You will have to fill in the rest.
public static IEnumerable<object> ExtractConstants<T>(
Expression<Action<T>> expression)
{
return extractConstants(expression);
}
private static IEnumerable<object> extractConstants(Expression expression)
{
if (expression == null)
yield break;
if (expression is ConstantExpression)
yield return ((ConstantExpression) expression).Value;
else if (expression is LambdaExpression)
foreach (var constant in extractConstants(
((LambdaExpression) expression).Body))
yield return constant;
else if (expression is UnaryExpression)
foreach (var constant in extractConstants(
((UnaryExpression) expression).Operand))
yield return constant;
else if (expression is MethodCallExpression)
{
foreach (var arg in ((MethodCallExpression) expression).Arguments)
foreach (var constant in extractConstants(arg))
yield return constant;
foreach (var constant in extractConstants(
((MethodCallExpression) expression).Object))
yield return constant;
}
else
throw new NotImplementedException();
}
For the case that you have mentioned, this already works:
// Prints:
// Jimmy (System.String)
// 1 (System.Int32)
foreach (var constant in Ext.ExtractConstants<string>(
str => Console.WriteLine("Jimmy", 1)))
Console.WriteLine("{0} ({1})", constant.ToString(),
constant.GetType().FullName);
For more complex lambda expressions that employ other types of expression nodes, you will have to incrementally extend the above code. Every time you use it and it throws a NotImplementedException, here is what I do:
Open the Watch window in the debugger
Look at the expression variable and its type
Add the necessary code to handle that expression type
Over time the method will become more and more complete.
public override IQueryable<Image> FindAll(System.Linq.Expressions.Expression<Func<Image, dynamic>> Id)
{
dynamic currentType = Id.Parameters[0];
var id = currentType.Type.GUID;
var result = (_uniwOfWork as UnitOfWork).uspGetImages(id.ToString());
return FindAll();
}
use keyword dynamic.
I have a variable number of OR conditions that I want to put together into one Linq query.
How do I do this in a loop? Basically, the final query is to be:
IQueryable<MyObject> Q;
Q = Q.Where(q => (condition1) || (condition2) || ..... || (condition N));
Something like:
For (int i = 0; i < someNumber; i++) {
Q = Q.Where(q => (existing conditions) || (q.Value == i));
}
What statement can I use to replace (existing condition) in example above without having the final expression (Q) have nested Q's inside them?
Thanks.
You'd need to build an expression tree representing all the conditions you were interested in, combined with Expression.OrElse, and then call Where a single time at the end.
This may be somewhat tricky if your current source is an anonymous type, but it shouldn't be too bad otherwise. Here's a sample - there may be a simpler way of doing the parameter replacement, but this isn't too bad. (Although ExpressionVisitor only works in .NET 4... you'd have to implement something similar yourself if you wanted to use this in .NET 3.5.)
using System;
using System.Linq;
using System.Linq.Expressions;
public class Test
{
static void Main()
{
IQueryable<string> strings = (new[] { "Jon", "Tom", "Holly",
"Robin", "William" }).AsQueryable();
Expression<Func<string, bool>> firstPredicate = p => p.Contains("ll");
Expression<Func<string, bool>> secondPredicate = p => p.Length == 3;
Expression combined = Expression.OrElse(firstPredicate.Body,
secondPredicate.Body);
ParameterExpression param = Expression.Parameter(typeof(string), "p");
ParameterReplacer replacer = new ParameterReplacer(param);
combined = replacer.Visit(combined);
var lambda = Expression.Lambda<Func<string, bool>>(combined, param);
var query = strings.Where(lambda);
foreach (string x in query)
{
Console.WriteLine(x);
}
}
// Helper class to replace all parameters with the specified one
class ParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression parameter;
internal ParameterReplacer(ParameterExpression parameter)
{
this.parameter = parameter;
}
protected override Expression VisitParameter
(ParameterExpression node)
{
return parameter;
}
}
}
A less-than-optimized version (pray that the backend will do the necessary lifting and optimization).
public static IQueryable<T> Any<T>(this IQueryable<T> q,
params Expression<Func<T, bool>>[] preds)
{
var par = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Constant(false);
foreach (var pred in preds)
{
body = Expression.OrElse(body, Expression.Invoke(pred, par));
}
var ff = Expression.Lambda(body, par) as Expression<Func<T, bool>>;
return q.Where(ff);
}
static void Main(string[] args)
{
var q = new[] { "jim", "bob", "Jon", "leppie" }.AsQueryable();
Expression<Func<string, bool>>[] preds =
{
x => x == "Jon",
x => x == "Skeet",
x => x == "leppie"
};
var result = q.Any(preds).ToArray();
}
public static IEnumerable<T> GetItemsThatMatchAny<T> (this IEnumerable<T> source, IEnumerable<Func<T,bool>> predicates)
{
return source.Where(t => predicates.Any(predicate => predicate(t)));
}
An example of a predicate generator:
private static IEnumerable<Func<MyClass, bool>> GetPredicates (int num)
{
var predicates = new Func<MyClass, bool>[] {m => m.Foo == 3, m => m.Bar =="x", m => DateTime.Now.DayOfWeek == DayOfWeek.Sunday};
return predicates.Take (num);
}
Given a class structure like this:
public class GrandParent
{
public Parent Parent { get; set;}
}
public class Parent
{
public Child Child { get; set;}
}
public class Child
{
public string Name { get; set;}
}
and the following method signature:
Expression<Func<TOuter, TInner>> Combine (Expression<Func<TOuter, TMiddle>>> first, Expression<Func<TMiddle, TInner>> second);
How can I implement said method so that I can call it like this:
Expression<Func<GrandParent, Parent>>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = Combine(myFirst, mySecond);
such that output ends up as:
gp => gp.Parent.Child.Name
Is this possible?
The contents of each Func will only ever be a MemberAccess. I'd rather not end up with output being a nested function call.
Thanks
OK; pretty long snippet, but here's a starter for an expression-rewriter; it doesn't handle a few cases yet (I'll fix it later), but it works for the example given and a lot of others:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
public class GrandParent
{
public Parent Parent { get; set; }
}
public class Parent
{
public Child Child { get; set; }
public string Method(string s) { return s + "abc"; }
}
public class Child
{
public string Name { get; set; }
}
public static class ExpressionUtils
{
public static Expression<Func<T1, T3>> Combine<T1, T2, T3>(
this Expression<Func<T1, T2>> outer, Expression<Func<T2, T3>> inner, bool inline)
{
var invoke = Expression.Invoke(inner, outer.Body);
Expression body = inline ? new ExpressionRewriter().AutoInline(invoke) : invoke;
return Expression.Lambda<Func<T1, T3>>(body, outer.Parameters);
}
}
public class ExpressionRewriter
{
internal Expression AutoInline(InvocationExpression expression)
{
isLocked = true;
if(expression == null) throw new ArgumentNullException("expression");
LambdaExpression lambda = (LambdaExpression)expression.Expression;
ExpressionRewriter childScope = new ExpressionRewriter(this);
var lambdaParams = lambda.Parameters;
var invokeArgs = expression.Arguments;
if (lambdaParams.Count != invokeArgs.Count) throw new InvalidOperationException("Lambda/invoke mismatch");
for(int i = 0 ; i < lambdaParams.Count; i++) {
childScope.Subst(lambdaParams[i], invokeArgs[i]);
}
return childScope.Apply(lambda.Body);
}
public ExpressionRewriter()
{
subst = new Dictionary<Expression, Expression>();
}
private ExpressionRewriter(ExpressionRewriter parent)
{
if (parent == null) throw new ArgumentNullException("parent");
subst = new Dictionary<Expression, Expression>(parent.subst);
inline = parent.inline;
}
private bool isLocked, inline;
private readonly Dictionary<Expression, Expression> subst;
private void CheckLocked() {
if(isLocked) throw new InvalidOperationException(
"You cannot alter the rewriter after Apply has been called");
}
public ExpressionRewriter Subst(Expression from,
Expression to)
{
CheckLocked();
subst.Add(from, to);
return this;
}
public ExpressionRewriter Inline() {
CheckLocked();
inline = true;
return this;
}
public Expression Apply(Expression expression)
{
isLocked = true;
return Walk(expression) ?? expression;
}
private static IEnumerable<Expression> CoalesceTerms(
IEnumerable<Expression> sourceWithNulls, IEnumerable<Expression> replacements)
{
if(sourceWithNulls != null && replacements != null) {
using(var left = sourceWithNulls.GetEnumerator())
using (var right = replacements.GetEnumerator())
{
while (left.MoveNext() && right.MoveNext())
{
yield return left.Current ?? right.Current;
}
}
}
}
private Expression[] Walk(IEnumerable<Expression> expressions) {
if(expressions == null) return null;
return expressions.Select(expr => Walk(expr)).ToArray();
}
private static bool HasValue(Expression[] expressions)
{
return expressions != null && expressions.Any(expr => expr != null);
}
// returns null if no need to rewrite that branch, otherwise
// returns a re-written branch
private Expression Walk(Expression expression)
{
if (expression == null) return null;
Expression tmp;
if (subst.TryGetValue(expression, out tmp)) return tmp;
switch(expression.NodeType) {
case ExpressionType.Constant:
case ExpressionType.Parameter:
{
return expression; // never a need to rewrite if not already matched
}
case ExpressionType.MemberAccess:
{
MemberExpression me = (MemberExpression)expression;
Expression target = Walk(me.Expression);
return target == null ? null : Expression.MakeMemberAccess(target, me.Member);
}
case ExpressionType.Add:
case ExpressionType.Divide:
case ExpressionType.Multiply:
case ExpressionType.Subtract:
case ExpressionType.AddChecked:
case ExpressionType.MultiplyChecked:
case ExpressionType.SubtractChecked:
case ExpressionType.And:
case ExpressionType.Or:
case ExpressionType.ExclusiveOr:
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.AndAlso:
case ExpressionType.OrElse:
case ExpressionType.Power:
case ExpressionType.Modulo:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.LeftShift:
case ExpressionType.RightShift:
case ExpressionType.Coalesce:
case ExpressionType.ArrayIndex:
{
BinaryExpression binExp = (BinaryExpression)expression;
Expression left = Walk(binExp.Left), right = Walk(binExp.Right);
return (left == null && right == null) ? null : Expression.MakeBinary(
binExp.NodeType, left ?? binExp.Left, right ?? binExp.Right, binExp.IsLiftedToNull,
binExp.Method, binExp.Conversion);
}
case ExpressionType.Not:
case ExpressionType.UnaryPlus:
case ExpressionType.Negate:
case ExpressionType.NegateChecked:
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
case ExpressionType.TypeAs:
case ExpressionType.ArrayLength:
{
UnaryExpression unExp = (UnaryExpression)expression;
Expression operand = Walk(unExp.Operand);
return operand == null ? null : Expression.MakeUnary(unExp.NodeType, operand,
unExp.Type, unExp.Method);
}
case ExpressionType.Conditional:
{
ConditionalExpression ce = (ConditionalExpression)expression;
Expression test = Walk(ce.Test), ifTrue = Walk(ce.IfTrue), ifFalse = Walk(ce.IfFalse);
if (test == null && ifTrue == null && ifFalse == null) return null;
return Expression.Condition(test ?? ce.Test, ifTrue ?? ce.IfTrue, ifFalse ?? ce.IfFalse);
}
case ExpressionType.Call:
{
MethodCallExpression mce = (MethodCallExpression)expression;
Expression instance = Walk(mce.Object);
Expression[] args = Walk(mce.Arguments);
if (instance == null && !HasValue(args)) return null;
return Expression.Call(instance, mce.Method, CoalesceTerms(args, mce.Arguments));
}
case ExpressionType.TypeIs:
{
TypeBinaryExpression tbe = (TypeBinaryExpression)expression;
tmp = Walk(tbe.Expression);
return tmp == null ? null : Expression.TypeIs(tmp, tbe.TypeOperand);
}
case ExpressionType.New:
{
NewExpression ne = (NewExpression)expression;
Expression[] args = Walk(ne.Arguments);
if (HasValue(args)) return null;
return ne.Members == null ? Expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments))
: Expression.New(ne.Constructor, CoalesceTerms(args, ne.Arguments), ne.Members);
}
case ExpressionType.ListInit:
{
ListInitExpression lie = (ListInitExpression)expression;
NewExpression ctor = (NewExpression)Walk(lie.NewExpression);
var inits = lie.Initializers.Select(init => new
{
Original = init,
NewArgs = Walk(init.Arguments)
}).ToArray();
if (ctor == null && !inits.Any(init => HasValue(init.NewArgs))) return null;
ElementInit[] initArr = inits.Select(init => Expression.ElementInit(
init.Original.AddMethod, CoalesceTerms(init.NewArgs, init.Original.Arguments))).ToArray();
return Expression.ListInit(ctor ?? lie.NewExpression, initArr);
}
case ExpressionType.NewArrayBounds:
case ExpressionType.NewArrayInit:
/* not quite right... leave as not-implemented for now
{
NewArrayExpression nae = (NewArrayExpression)expression;
Expression[] expr = Walk(nae.Expressions);
if (!HasValue(expr)) return null;
return expression.NodeType == ExpressionType.NewArrayBounds
? Expression.NewArrayBounds(nae.Type, CoalesceTerms(expr, nae.Expressions))
: Expression.NewArrayInit(nae.Type, CoalesceTerms(expr, nae.Expressions));
}*/
case ExpressionType.Invoke:
case ExpressionType.Lambda:
case ExpressionType.MemberInit:
case ExpressionType.Quote:
throw new NotImplementedException("Not implemented: " + expression.NodeType);
default:
throw new NotSupportedException("Not supported: " + expression.NodeType);
}
}
}
static class Program
{
static void Main()
{
Expression<Func<GrandParent, Parent>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> outputWithInline = myFirst.Combine(mySecond, false);
Expression<Func<GrandParent, string>> outputWithoutInline = myFirst.Combine(mySecond, true);
Expression<Func<GrandParent, string>> call =
ExpressionUtils.Combine<GrandParent, Parent, string>(
gp => gp.Parent, p => p.Method(p.Child.Name), true);
unchecked
{
Expression<Func<double, double>> mathUnchecked =
ExpressionUtils.Combine<double, double, double>(x => (x * x) + x, x => x - (x / x), true);
}
checked
{
Expression<Func<double, double>> mathChecked =
ExpressionUtils.Combine<double, double, double>(x => x - (x * x) , x => (x / x) + x, true);
}
Expression<Func<int,int>> bitwise =
ExpressionUtils.Combine<int, int, int>(x => (x & 0x01) | 0x03, x => x ^ 0xFF, true);
Expression<Func<int, bool>> logical =
ExpressionUtils.Combine<int, bool, bool>(x => x == 123, x => x != false, true);
Expression<Func<int[][], int>> arrayAccess =
ExpressionUtils.Combine<int[][], int[], int>(x => x[0], x => x[0], true);
Expression<Func<string, bool>> isTest =
ExpressionUtils.Combine<string,object,bool>(s=>s, s=> s is Regex, true);
Expression<Func<List<int>>> f = () => new List<int>(new int[] { 1, 1, 1 }.Length);
Expression<Func<string, Regex>> asTest =
ExpressionUtils.Combine<string, object, Regex>(s => s, s => s as Regex, true);
var initTest = ExpressionUtils.Combine<int, int[], List<int>>(i => new[] {i,i,i},
arr => new List<int>(arr.Length), true);
var anonAndListTest = ExpressionUtils.Combine<int, int, List<int>>(
i => new { age = i }.age, i => new List<int> {i, i}, true);
/*
var arrBoundsInit = ExpressionUtils.Combine<int, int[], int[]>(
i => new int[i], arr => new int[arr[0]] , true);
var arrInit = ExpressionUtils.Combine<int, int, int[]>(
i => i, i => new int[1] { i }, true);*/
}
}
I am assuming that your goal is to obtain the expression tree that you would have obtained, had you actually compiled the "combined" lambda. It's much easier to construct a new expression tree that simply invokes the given expression trees appropriately, but I assume that's not what you want.
extract the body of first, cast it to MemberExpression. Call this firstBody.
extract the body of second, call this secondBody
extract the parameter of first. Call this firstParam.
extract the parameter of second. Call this secondParam.
Now, the hard part. Write a visitor pattern implementation which searches through secondBody looking for the single usage of secondParam. (This will be much easier if you know that it's only member access expressions, but you can solve the problem in general.) When you find it, construct a new expression of the same type as its parent, substituting in firstBody for the parameter. Continue to rebuild the transformed tree on the way back out; remember, all you have to rebuild is the "spine" of the tree that contains the parameter reference.
the result of the visitor pass will be a rewritten secondBody with no occurrences of secondParam, only occurences of expressions involving firstParam.
construct a new lambda expression with that body as its body, and firstParam as its param.
and you're done!
Matt Warren's blog might be a good thing for you to read. He designed and implemented all this stuff and has written a lot about ways to rewrite expression trees effectively. (I only did the compiler end of things.)
UPDATE:
As this related answer points out, in .NET 4 there is now a base class for expression rewriters that makes this sort of thing a lot easier.
I'm not sure what you mean by it not being a nested function call, but this will do the trick - with an example:
using System;
using System.IO;
using System.Linq.Expressions;
class Test
{
static Expression<Func<TOuter, TInner>> Combine<TOuter, TMiddle, TInner>
(Expression<Func<TOuter, TMiddle>> first,
Expression<Func<TMiddle, TInner>> second)
{
var parameter = Expression.Parameter(typeof(TOuter), "x");
var firstInvoke = Expression.Invoke(first, new[] { parameter });
var secondInvoke = Expression.Invoke(second, new[] { firstInvoke} );
return Expression.Lambda<Func<TOuter, TInner>>(secondInvoke, parameter);
}
static void Main()
{
Expression<Func<int, string>> first = x => (x + 1).ToString();
Expression<Func<string, StringReader>> second = y => new StringReader(y);
Expression<Func<int, StringReader>> output = Combine(first, second);
Func<int, StringReader> compiled = output.Compile();
var reader = compiled(10);
Console.WriteLine(reader.ReadToEnd());
}
}
I don't know how efficient the generated code will be compared with a single lambda expression, but I suspect it won't be too bad.
For a complete solution have a look at LINQKit:
Expression<Func<GrandParent, string>> output = gp => mySecond.Invoke(myFirst.Invoke(gp));
output = output.Expand().Expand();
output.ToString() prints out
gp => gp.Parent.Child.Name
whereas Jon Skeet's solution yields
x => Invoke(p => p.Child.Name,Invoke(gp => gp.Parent,x))
I guess that's what you're referring to as 'nested function calls'.
Try this:
public static Expression<Func<TOuter, TInner>> Combine<TOuter, TMiddle, TInner>(
Expression<Func<TOuter, TMiddle>> first,
Expression<Func<TMiddle, TInner>> second)
{
return x => second.Compile()(first.Compile()(x));
}
and the usage:
Expression<Func<GrandParent, Parent>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = Combine(myFirst, mySecond);
var grandParent = new GrandParent
{
Parent = new Parent
{
Child = new Child
{
Name = "child name"
}
}
};
var childName = output.Compile()(grandParent);
Console.WriteLine(childName); // prints "child name"
public static Expression<Func<T, TResult>> And<T, TResult>(this Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, TResult>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
After a half-day's digging came up with the following solution (much simpler than the accepted answer):
For generic lambda composition:
public static Expression<Func<X, Z>> Compose<X, Y, Z>(Expression<Func<Y, Z>> f, Expression<Func<X, Y>> g)
{
return Expression.Lambda<Func<X, Z>>(Expression.Invoke(f, Expression.Invoke(g, g.Parameters[0])), g.Parameters);
}
This combines two expressions in one, i.e. applies the first expression to the result of the second.
So if we have f(y) and g(x), combine(f,g)(x) === f(g(x))
Transitive and associative, so the combinator can be chained
More specifically, for property access (needed for MVC/EF):
public static Expression<Func<X, Z>> Property<X, Y, Z>(Expression<Func<X, Y>> fObj, Expression<Func<Y, Z>> fProp)
{
return Expression.Lambda<Func<X, Z>>(Expression.Property(fObj.Body, (fProp.Body as MemberExpression).Member as PropertyInfo), fObj.Parameters);
}
Note: fProp must be a simple property access expression, such as x => x.Prop.
fObj can be any expression (but must be MVC-compatible)
With a toolkit called Layer Over LINQ, there's an extension method that does exactly this, combines two expressions to create a new one suitable for use in LINQ to Entities.
Expression<Func<GrandParent, Parent>>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = myFirst.Chain(mySecond);