简体   繁体   English

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

[英]Retrieving an Expression from a property and adding it to an expression tree

I've tried to simplify this example, as the actual code I'm playing with is more complex. 我试图简化这个例子,因为我正在玩的实际代码更复杂。 So while this example may seem silly, bear with me. 所以虽然这个例子看起来很傻,但请耐心等待。 Let's say I'm working with the AdventureWorks database and I decide I want to add a property called Blarg to the Product table that returns an expression that contains code I would like to use in several places: 假设我正在使用AdventureWorks数据库,我决定将一个名为Blarg的属性添加到Product表中,该表返回一个表达式,其中包含我想在几个地方使用的代码:

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

What I want to do is create an expression expression tree, have it get the Expression from Product.Blarg, and group by the result. 我想要做的是创建一个表达式表达式树,让它从Product.Blarg获取Expression,并按结果分组。 Something like this: 像这样的东西:

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]]'."
}

Obviously groupExpression is incorrect (see the code comment for the exception), but I'm not sure how I should be doing it. 显然groupExpression是不正确的(请参阅异常的代码注释),但我不确定我应该怎么做。 What I thought I was saying is "get the Expression from the product.Blarg , execute it, and return the string result." 我以为我说的是“从product.Blarg获取表达式,执行它,并返回字符串结果。” I guess that's not what I'm actually saying there, though. 我猜这不是我实际上在那里说的。 I'm still trying to figure out expression trees. 我还在试图找出表达树。 Any idea how I could pull this off? 知道我怎么能把它拉下来吗?

When you call Expression.Invoke , the first argument must be an existing LambdaExpression - it can't be an Expression to a LambdaExpression . 当你调用Expression.Invoke ,第一个参数必须是现有LambdaExpression -它不能是一个Expression LambdaExpression Or in other words: it isn't going to evaluate Product.Blarg per row and use a different sub-expression each time. 换句话说:它不会每行评估Product.Blarg 每次都使用不同的子表达式。

Instead, you would retrieve this lambda first, perhaps making it static and accessing it via reflection if you only know it by name: 相反,您将首先检索此lambda,或许将其设置为static并通过反射访问它,如果您只知道它的名称:

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

And pass lambda in as the argument to Expression.Invoke ; 并将lambda作为参数传递给Expression.Invoke ; here's a fully working LINQ-to-Objects example showing this (via AsQueryable() ): 这是一个完整工作的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();
    }
}
var qry = data.AsQueryable().GroupBy(Blarg).ToList();

That works, same as Marc's code. 这与Marc的代码相同。

Note: Blarg is already correct, there is no reason to 're-invoke' it. 注意: Blarg已经正确,没有理由“重新调用”它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM