views:

112

answers:

4

Lets say i have :

 Func<Customer,bool > a = (c) => c.fullName == "John";

now i want to convert to expressiontree any way to do that ?

i know i can define it from the first place as expressiontree but the situation i have is different because i must concatenate some lambda expressions first then pass it to a method which take expressiontree, doing so result in compile time error!

example:

        Func<Customer, bool> a = (c) => c.fullName == "John";
        Func<Customer, bool> b = (c) => c.LastName == "Smith";
        Func<Customer, bool> final = c => a(c) && b(c); 

now i want to pass final to a method which takes

ExpressionTree<Func<Customer,bool >>

it gives compile time error

thanks in advance

+4  A: 

You cannot do that. A variable of type Func<...> is a delegate, which is basically like a pointer to a memory location that contains the compiled code for the lambda expression. There is no functionality in .NET to turn already-compiled code back into an expression tree.

Depending on what you are trying to do, maybe you can contend with an incomplete solution: create an expression tree that calls the delegates. Since I don’t know anything about the method to which you want to pass the expression tree, I have no idea whether this is at all a feasible solution for you.

Summary: If you want the complete expression tree of all the expressions, you need to make sure that they are expression trees right from the start. As soon as you compile it into a delegate, the expression tree is lost.

Once you’ve made sure that they are expression trees, you can combine them using something like the following:

Expression<Func<Customer, bool>> a = c => c.FullName == "John";
Expression<Func<Customer, bool>> b = c => c.LastName == "Smith";

var cp = Expression.Parameter(typeof(Customer), "c");

var ai = Expression.Invoke(a, cp);
var bi = Expression.Invoke(b, cp);

var final = Expression.Lambda<Func<Customer, bool>>(
    Expression.AndAlso(ai, bi), cp);

Of course, this uses the AndAlso operator (&&); you can also use OrElse for || etc.

Timwi
then that arise new question or change the question to How do i concatenate Expression Trees !!!
Stacker
Answer updated.
Timwi
+2  A: 

You can go from Expression to a Func, but not the other way around.

You can do this:

Expression<Func<Customer, bool>> exprA = (c) => c.fullName == "John";
Func<Customer, bool> funcA = exprA.Compile();

But there's no way to go the other way.

Shlomo
+1  A: 

Regarding your revised question, I think this will work:

Expression<Func<Customer, bool>> a = (c) => c.FullName == "John";
Expression<Func<Customer, bool>> b = (c) => c.LastName == "Smith";

var cp = Expression.Parameter(typeof(Customer), "c");

var ai = Expression.Invoke(a, cp);
var bi = Expression.Invoke(b, cp);

var final = Expression.Lambda<Func<Customer, bool>>(Expression.And(ai, bi), cp);
Daniel Pratt
+1  A: 

Here is a solution that I think will work for you. I converts a Func<TInput, TOutput> to a Expression<Func<TInput, TOutput>>.

It was based in this post from ElegantCode

In this example I used a Func:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        public static bool Method(Expression<Func<int, bool>> predicate, int value)
        {
            return predicate.Compile()(value);
        }

        static void Main(string[] args)
        {
            Func<int, bool> testPredicate = n => n == 1;
            var output = ConvertFuncToExpression(testPredicate);
            Console.WriteLine(Method(output, 3));
            Console.WriteLine(Method(output, 1));
        }

        private static Expression<TDelegate> CreateExpression<TDelegate>(MethodBase method)
        {
            var delegateArguments = typeof(TDelegate).GetMethod("Invoke").GetParameters().Select((parameter, index) => Expression.Parameter(parameter.ParameterType, "param_" + index)).ToArray();
            if (delegateArguments.Count() != method.GetParameters().Count()) throw new InvalidOperationException("The number of parameters of the requested delegate does not match the number parameters of the specified method.");

            var argumentsTypes = method.GetGenericArguments();
            argumentsTypes = (argumentsTypes.Length > 0) ? argumentsTypes : null;
            var convertedArguments = method.GetParameters().Select((parameter, index) => Expression.Convert(delegateArguments[index], parameter.ParameterType)).ToArray();
            var call = Expression.Call(method.DeclaringType, method.Name, argumentsTypes, convertedArguments);

            var lambda = Expression.Lambda<TDelegate>(call, delegateArguments);
            return lambda;
        }

        private static Expression<Func<TIn1, TOut>> ConvertFuncToExpression<TIn1, TOut>(Func<TIn1, TOut> input)
        {
            MethodInfo method = input.Method;
            return CreateExpression<Func<TIn1, TOut>>(method);
        }
    }
}
Sir Gallahad
Is it just me or is just a very elaborate way of saying `var p = Expression.Parameter(typeof(TInput)); return (Expression<Func<TInput, TOutput>>) Expression.Lambda(Expression.Call(Expression.Constant(input.Target), input.Method, p), p);`? The blog post you linked to only goes for all this trouble because it tries to convert a `MethodInfo`, rather than an already-strongly-typed `Func<>`.
Timwi
Because the ConvertFunc is a simplification I added for the sake of this sample. The CreateExpression (which really does the convertion) can conver a delegate with any number of arguments (Func<TIn1, TIn2, ... TInN, TOut>) not only one. I agree that it can be simplified but it works fine.
Sir Gallahad
Just rewrite it to make it look less complex...
Sir Gallahad