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

Pie*_*ant 7 c# lambda expression-trees

我有两个表达式树定义如下:

private Expression<Func<TEntity, TPropertyResult>> PropertyAccessor { get; set; }
Run Code Online (Sandbox Code Playgroud)

private Expression<Func<TPropertyResult, bool>> TestExpression { get; set; }
Run Code Online (Sandbox Code Playgroud)

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

var expression = p => this.TestExpression(this.PropertyAccessor(p));
Run Code Online (Sandbox Code Playgroud)

使用时Expression.Invoke(this.TestExpression, this.PropertyAccessor),我收到以下错误

{"类型'System.Func`2 [MyEntity,System.String]'的表达式不能用于'System.String'类型的参数"}

TPropertyResult 我测试时是一个字符串.

我试过用Expression.Call或者Expression.Invoke.没运气.我该怎么用?

Tim*_*mwi 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

但是,重新阅读原始问题(在编辑之前),我开始觉得你提出错误的问题并且你可能不需要表达式树.如果你需要的只是函数,那么你可以使用它们而不需要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));
    }
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

// 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);
Run Code Online (Sandbox Code Playgroud)