将表达式树作为参数传递给另一个表达式树

时间:2010-08-19 01:36:57

标签: c# lambda expression-trees

我有两个这样定义的表达式树:

private Expression<Func<TEntity, TPropertyResult>> PropertyAccessor { get; set; }

private Expression<Func<TPropertyResult, bool>> TestExpression { get; set; }

我需要创建一个新的表达式树,它将产生相当于:

var expression = p => this.TestExpression(this.PropertyAccessor(p));

使用Expression.Invoke(this.TestExpression, this.PropertyAccessor)时,出现以下错误

  

{“类型的表达   'System.Func`2 [myEntity所,System.String]'   不能用于类型的参数   'System.String'“}

我的测试中

TPropertyResult是一个字符串。

我尝试使用Expression.CallExpression.Invoke。没运气。我该怎么用?

2 个答案:

答案 0 :(得分:8)

我认为这符合您的要求:

Expression<Func<TEntity, bool>> Combined
{
    get
    {
        var entity = Expression.Parameter(typeof(TEntity));
        var pa = Expression.Invoke(PropertyAccessor, entity);
        var te = Expression.Invoke(TestExpression, pa);
        return (Expression<Func<TEntity, bool>>) Expression.Lambda(te, entity);
    }
}

我对此进行了测试,它的工作正如我所料。

但是,重新阅读原始问题(在编辑之前),我开始觉得你提出了错误的问题并且你可能不需要表达式树。如果您只需要功能,那么您可以在没有Expression的情况下使用它们:

private Func<TEntity, TPropertyResult> PropertyAccessor { get; set; }
private Func<TPropertyResult, bool> TestExpression { get; set; }
private Func<TEntity, bool> Combined
{
    get
    {
        return entity => TestExpression(PropertyAccessor(entity));
    }
}

使用示例:

// Set up the original functions
PropertyAccessor = entity => GenerateResult(entity);
TestExpression = result => result.IsCool();

// This stores a reference to the combined function
var fn = Combined;

// This actually evaluates the function
bool isCool = fn(myEntity);

// Alternatively, you could evaluate the function directly, without the variable
bool isCool = Combined(myEntity);

答案 1 :(得分:0)

我发现最简单的方法是使用LinqKit(https://github.com/scottksmith95/LINQKit

有了它,您实际上可以做到

var expression = p => this.TestExpression.Invoke(this.PropertyAccessor(p));
db.Users.Where(expression.Expand());

LinqKit附带了Expand,它在这里具有神奇的作用,即使表达式中包含Invoke,它也允许EF转换为SQL。