从属性中检索表达式并将其添加到表达式树中

时间:2009-10-21 10:36:32

标签: c# .net linq-to-sql expression-trees

我试图简化这个例子,因为我正在使用的实际代码更复杂。所以虽然这个例子看起来很傻,但请耐心等待。假设我正在使用AdventureWorks数据库,我决定在Blarg表中添加一个名为Product的属性,该表返回一个表达式,其中包含我想在几个地方使用的代码: / p>

public partial class Product
{
    public Expression<Func<Product, string>> Blarg
    {
        get { return product => product.ProductModelID.HasValue ? "Blarg?" : "Blarg!"; }
    }
}

我想要做的是创建一个表达式表达式树,让它从Product.Blarg获取Expression,并按结果分组。像这样:

var productParameter = Expression.Parameter(typeof(Product), "product");

// The Problem
var groupExpression = Expression.Lambda<Func<Product, string>>(
    Expression.Invoke(
        Expression.Property(productParameter, "Blarg"), 
        productParameter), 
    productParameter);

using (AdventureWorksDataContext db = new AdventureWorksDataContext())
{
    var result = db.Products.GroupBy(groupExpression).ToList();
    // Throws ArgumentException: "The argument 'value' was the wrong type. 
    //  Expected 'System.Delegate'. 
    //  Actual 'System.Linq.Expressions.Expression`1[System.Func`2[LINQ_Test.Product,System.String]]'."
}

显然groupExpression不正确(请参阅异常的代码注释),但我不确定应该怎么做。我以为我说的是“从product.Blarg获取表达式,执行它,并返回字符串结果。”我猜这不是我实际上在那里说的。我还在试图找出表达树。知道如何把它拉下来吗?

2 个答案:

答案 0 :(得分:3)

当您致电Expression.Invoke时,第一个参数必须是现有LambdaExpression - 它不能是Expression a LambdaExpression 。换句话说:它不会每行评估Product.Blarg 并且每次都使用不同的子表达式。

相反,您将首先检索此lambda,或者将其设为static并通过反射访问它,如果您只知道它的名称:

var lambda = (LambdaExpression) typeof(Product)
          .GetProperty("Blarg").GetValue(null,null);

并将lambda作为参数传递给Expression.Invoke;这是一个完整工作的LINQ-to-Objects示例,显示了这一点(通过AsQueryable()):

using System;
using System.Linq;
using System.Linq.Expressions;
public partial class Product
{
    public static Expression<Func<Product, string>> Blarg
    {
        get { return product => product.ProductModelID.HasValue ? "Blarg?" : "Blarg!"; }
    }
    public int? ProductModelID { get; set; }

    static void Main()
    {
        var lambda = (LambdaExpression)typeof(Product)
          .GetProperty("Blarg").GetValue(null, null);

        var productParameter = Expression.Parameter(typeof(Product), "product");

        // The Problem
        var groupExpression = Expression.Lambda<Func<Product, string>>(
            Expression.Invoke(
                lambda,
                productParameter),
            productParameter);

        var data = new[] {
            new Product { ProductModelID = 123},
            new Product { ProductModelID = null},
            new Product { ProductModelID = 456},
        };
        var qry = data.AsQueryable().GroupBy(groupExpression).ToList();
    }
}

答案 1 :(得分:3)

var qry = data.AsQueryable().GroupBy(Blarg).ToList();

有效,与Marc的代码相同。

注意:Blarg已经正确,没有理由“重新调用”它。