4

我试图简化这个例子,因为我正在使用的实际代码更复杂。因此,虽然这个例子可能看起来很愚蠢,但请耐心等待。假设我正在使用 AdventureWorks 数据库,并且我决定添加一个名为的属性,该属性返回一个包含我想在多个地方使用的代码的表达式Blarg的表:Product

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

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

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,执行它,然后返回字符串结果。” 不过,我想这不是我实际上要说的。我仍在尝试找出表达式树。知道我怎么能做到这一点吗?

4

2 回答 2

3

当您调用Expression.Invoke时,第一个参数必须是现有的LambdaExpression- 它不能是 aExpression 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();
    }
}
于 2009-10-21T11:37:46.387 回答
3
var qry = data.AsQueryable().GroupBy(Blarg).ToList();

这和 Marc 的代码一样有效。

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

于 2009-10-21T11:50:52.953 回答