我想结合两个LambdaExpressions而不编译它们。
如果我编译它们就是这样:
public Expression<Func<TContainer,bool>> CreatePredicate<TContainer,TMember>(
Expression<Func<TContainer,TMember>> getMemberExpression,
Expression<Func<TMember,bool>> memberPredicateExpression)
{
return x => memberPredicateExpression.Compile()(getMemberExpression.Compile()(x));
}
这显然不是从提供的参数中获取目标表达式的最快方法。此外,它使它与不支持C#方法调用的LINQ to SQL等查询提供程序不兼容。
从我读过的内容来看,似乎最好的方法是构建一个ExpressionVisitor
类。然而,这似乎是一个非常常见的任务。有谁知道现有的开源代码库提供这种功能?如果不是,那么接近ExpressionVisitor
以使其尽可能通用的最佳方法是什么?
答案 0 :(得分:4)
我不知道这是不是最好的方法,但你可以这样做:
public Expression<Func<TContainer,bool>> CreatePredicate<TContainer,TMember>(
Expression<Func<TContainer,TMember>> getMemberExpression,
Expression<Func<TMember,bool>> memberPredicateExpression)
{
ParameterExpression x = Expression.Parameter(typeof(TContainer), "x");
return Expression.Lambda<Func<TContainer, bool>>(
Expression.Invoke(
memberPredicateExpression,
Expression.Invoke(
getMemberExpression,
x)),
x);
}
用法:
var expr = CreatePredicate(
(Foo f) => f.Bar,
bar => bar % 2 == 0);
结果:
x => Invoke(bar => ((bar % 2) == 0), Invoke(f => f.Bar, x))
我想最好得到像x => x.Bar % 2 == 0
这样的东西,但它可能会更难......
编辑:实际上,表达访问者并不是那么难:
public Expression<Func<TContainer,bool>> CreatePredicate<TContainer,TMember>(
Expression<Func<TContainer,TMember>> getMemberExpression,
Expression<Func<TMember,bool>> memberPredicateExpression)
{
return CombineExpressionVisitor.Combine(
getMemberExpression,
memberPredicateExpression);
}
class CombineExpressionVisitor : ExpressionVisitor
{
private readonly ParameterExpression _parameterToReplace;
private readonly Expression _replacementExpression;
private CombineExpressionVisitor(ParameterExpression parameterToReplace, Expression replacementExpression)
{
_parameterToReplace = parameterToReplace;
_replacementExpression = replacementExpression;
}
public static Expression<Func<TSource, TResult>> Combine<TSource, TMember, TResult>(
Expression<Func<TSource, TMember>> memberSelector,
Expression<Func<TMember, TResult>> resultSelector)
{
var visitor = new CombineExpressionVisitor(
resultSelector.Parameters[0],
memberSelector.Body);
return Expression.Lambda<Func<TSource, TResult>>(
visitor.Visit(resultSelector.Body),
memberSelector.Parameters);
}
protected override Expression VisitParameter(ParameterExpression parameter)
{
if (parameter == _parameterToReplace)
return _replacementExpression;
return base.VisitParameter(parameter);
}
}
它给出以下表达式:
f => ((f.Bar % 2) == 0)