我有两个这样定义的表达式树:
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.Call
或Expression.Invoke
。没运气。我该怎么用?
答案 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。