【问题标题】:Passing an expression tree as a parameter to another expression tree将表达式树作为参数传递给另一个表达式树
【发布时间】:2010-08-19 01:36:56
【问题描述】:

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

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 的内容不足以完成您想要完成的任务吗?
  • 使用 Invoke 时,提示:{"Expression of type 'System.Func2[MyEntity,System.String]' cannot be used for parameter of type 'System.String'"}. That is when I try to specify a string as the TPropertyResult`,但是问题不限于字符串。

标签: c# lambda expression-trees


【解决方案1】:

我认为这可以满足您的要求:

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&lt;T&gt; 无处不在。
  • Marc Gravell 在 InfoQ 上有一篇很棒的文章,介绍了如何以及为什么应该使用 Expression 以及一些很好的具体示例。 infoq.com/articles/expression-compiler
  • 谢谢,我需要在linq to sql 中使用它,但出现此错误:The LINQ expression node type 'Invoke' is not supported in LINQ to Entities. 你能帮帮我吗?
【解决方案2】:

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

有了它你真的可以做到

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

Expand 带有 LinqKit 并在这里发挥了作用,它允许 EF 能够将 Invoke 转换为 SQL,尽管您的表达式中有 Invoke。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多