将Func <T>重构为Expression <Func <T >>

Ecy*_*yrb 5 .net c# expression-trees linq-to-sql

我有一个方法,目前Func<Product, string>作为一个参数,但我需要它作为一个Expression<Func<Product, string>>.使用AdventureWorks,这是我想用Func做的一个例子.

private static void DoSomethingWithFunc(Func<Product, string> myFunc)
{
    using (AdventureWorksDataContext db = new AdventureWorksDataContext())
    {
        var result = db.Products.GroupBy(product => new
        {
            SubCategoryName = myFunc(product),
            ProductNumber = product.ProductNumber
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望它看起来像这样:

private static void DoSomethingWithExpression(Expression<Func<Product, string>> myExpression)
{
    using (AdventureWorksDataContext db = new AdventureWorksDataContext())
    {
        var result = db.Products.GroupBy(product => new
            {
                SubCategoryName = myExpression(product),
                ProductNumber = product.ProductNumber
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我遇到的问题myExpression(product)是无效(不会编译).阅读其他一些帖子后,我理解为什么.如果不是因为我需要product变量用于我的密钥的第二部分,我可能会说这样的事情:

var result = db.Products.GroupBy(myExpression);
Run Code Online (Sandbox Code Playgroud)

但我确实需要product变量,因为我确实需要密钥的第二部分(ProductNumber).所以我现在不确定要做什么.我不能把它当成Func,因为这会导致问题.我无法弄清楚如何使用Expression,因为我没有看到如何将product变量传递给它.有任何想法吗?

编辑:以下是我将如何调用该方法的示例:

DoSomethingWithFunc(product => product.ProductSubcategory.Name);
Run Code Online (Sandbox Code Playgroud)

Pav*_*aev 4

无法将表示为Expression<T>对象的表达式树拼接到由 lambda 表达式表示的“树文字”的中间。您必须构建一个表达式树来GroupBy手动传递:

// Need an explicitly named type to reference in typeof()
private class ResultType
{
     public string SubcategoryName { get; set; }
     public int ProductNumber { get; set; }|
}

private static void DoSomethingWithExpression(
    Expression<Func<Product,
    string>> myExpression)
{
    var productParam = Expression.Parameter(typeof(Product), "product");
    var groupExpr = (Expression<Func<Product, ResultType>>)Expression.Lambda(
        Expression.MemberInit(
           Expression.New(typeof(ResultType)),
           Expression.Bind(
               typeof(ResultType).GetProperty("SubcategoryName"),
               Expression.Invoke(myExpression, productParam)),
           Expression.Bind(
               typeof(ResultType).GetProperty("ProductNumber"),
               Expression.Property(productParam, "ProductNumber"))),
        productParam);
    using (AdventureWorksDataContext db = new AdventureWorksDataContext())
    {
        var result = db.Products.GroupBy(groupExpr);
    }
}
Run Code Online (Sandbox Code Playgroud)