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

9

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

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,但没有成功。我应该使用什么?

编译器错误是什么?此外,代码不太易读。你确定 .Net 2.0 的东西不能满足你的需求吗? - Hamish Grubijan
使用Invoke时,它会显示:{"无法将类型为 'System.Func2[MyEntity,System.String]' 的表达式用于类型为 'System.String' 的参数"}。这是当我尝试将字符串指定为 TPropertyResult` 时出现的问题,但问题并不仅限于字符串。 - Pierre-Alain Vigeant
2个回答

9
我认为这个可以满足你的要求:
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);

哇,谢谢你提供这个可行的答案。我深入研究表达式时有些超出了我的能力范围。我想看 ASP.NET MVC 代码会让你认为 Expression<T> 在任何地方都是必需的。 - Pierre-Alain Vigeant
Marc Gravell在InfoQ上有一篇很棒的文章,介绍了如何以及为什么要使用Expression,并提供了一些好的具体示例。http://www.infoq.com/articles/expression-compiler - David Robbins
1
谢谢,我需要在 linq to sql 中使用它,但是出现了这个错误:The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. 你能帮我吗? - Mohsen

0

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

使用它,您实际上可以执行以下操作

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

Expand是与LinqKit一起提供的,它在这里发挥了魔力,它允许EF能够进行SQL翻译,尽管您的表达式中有Invoke。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接