我有一个方法,当前需要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
});
}
}
我希望它看起来像这样:
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
});
}
}
但是,我遇到的问题是myExpression(product)
无效(不会编译)。阅读其他一些帖子后,我理解为什么。如果不是因为我的密钥的第二部分需要product
变量,我可能会这样说:
var result = db.Products.GroupBy(myExpression);
但我确实需要product
变量,因为我确实需要密钥的第二部分(ProductNumber)。所以我现在不确定要做什么。我不能把它当成Func,因为这会导致问题。我无法弄清楚如何使用Expression,因为我看不出如何将product
变量传递给它。有什么想法吗?
编辑:以下是我将如何调用该方法的示例:
DoSomethingWithFunc(product => product.ProductSubcategory.Name);
答案 0 :(得分: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);
}
}
答案 1 :(得分:3)
第二个想法,编译表达式是行不通的。
您需要手动构建GroupBy表达式,这意味着您不能使用匿名类型。我建议构建表达式的其余部分,然后反编译以查看生成的表达式树。最终结果将类似于此,使用myExpression
的部分内容:
private static void DoSomethingWithExpression(Expression<Func<Product, string>> myExpression)
{
var productParam = myExpression.Parameters[0];
ConstructorInfo constructor = ...; // Get c'tor for return type
var keySelector = Expression.Lambda(
Expression.New(constructor,
new Expression[] {
productParam.Body,
... // Expressions to init other members
},
new MethodInfo[] { ... }), // Setters for your members
new [] { productParam });
using (AdventureWorksDataContext db = new AdventureWorksDataContext())
{
var result = db.Products.GroupBy(keySelector);
// ...
}
}