表达式的Func或Predicate

时间:2010-08-10 12:06:02

标签: c# linq lambda predicate

让我们说:

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

现在我想以任何方式转换为expressiontree吗?

我知道我可以从第一个地方定义它作为expressiontree但是我的情况不同,因为我必须首先连接一些lambda表达式然后将它传递给一个采用expressiontree的方法,这样做会导致编译时错误!

示例:

        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); 

现在我想将final传递给一个带

的方法
ExpressionTree<Func<Customer,bool >>

它给出了编译时错误

提前致谢

4 个答案:

答案 0 :(得分:5)

你做不到。类型Func<...>的变量是委托,它基本上类似于指向包含lambda表达式的编译代码的内存位置的指针。 .NET中没有任何功能可以将已编译的代码转换回表达式树。

根据您要做的事情,也许您可​​以使用不完整的解决方案:创建一个调用委托的表达式树。由于我对你想要传递表达式树的方法一无所知,我不知道这对你来说是否是一个可行的解决方案。

总结:如果你想要所有表达式的完整表达式树,你需要确保它们从一开始就是表达式树。只要将其编译为委托,表达式树就会丢失。

一旦确定它们是表达式树,就可以使用以下内容组合它们:

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);

当然,这会使用AndAlso运算符(&&);您也可以将OrElse用于||等。

答案 1 :(得分:2)

你可以从Expression转到Func,但不是相反。

你可以这样做:

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

但是没有办法走另一条路。

答案 2 :(得分:2)

关于你修改过的问题,我认为这样可行:

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);

答案 3 :(得分:1)

这是我认为适合您的解决方案。我将Func<TInput, TOutput>转换为Expression<Func<TInput, TOutput>>

它位于ElegantCode的this post

在这个例子中,我使用了一个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);
        }
    }
}