C# 重构函数<;T>;变成表达<;Func<;T>&燃气轮机;
我有一个方法,当前将C# 重构函数<;T>;变成表达<;Func<;T>&燃气轮机;,c#,.net,linq-to-sql,expression-trees,C#,.net,Linq To Sql,Expression Trees,我有一个方法,当前将Func作为参数,但我需要它是表达式。使用AdventureWorks,下面是一个我想使用Func做的示例 private static void DoSomethingWithFunc(Func<Product, string> myFunc) { using (AdventureWorksDataContext db = new AdventureWorksDataContext()) { var result = db.Pro
Func
作为参数,但我需要它是表达式
。使用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
});
}
}
但是我确实需要product
变量,因为我确实需要键的第二部分(ProductNumber)。所以我不确定现在该怎么办。我不能把它作为一个函数,因为这会引起问题。我不知道如何使用表达式,因为我不知道如何将product
变量传递给它。有什么想法吗
EDIT:下面是一个如何调用该方法的示例:
DoSomethingWithFunc(product => product.ProductSubcategory.Name);
再想一想,编译表达式是行不通的 您需要手工构建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);
// ...
}
}
private static void DoSomethingWithExpression(表达式myExpression)
{
var productParam=myExpression.Parameters[0];
ConstructorInfo构造函数=…;//获取返回类型的c'tor
var keySelector=Expression.Lambda(
表达式.New(构造函数,
新表达式[]{
productParam.Body,
…//初始化其他成员的表达式
},
new MethodInfo[]{…}),//成员的设置程序
新[]{productParam});
使用(AdventureWorksDataContext db=new AdventureWorksDataContext())
{
var结果=db.Products.GroupBy(keySelector);
// ...
}
}
无法将表示为表达式的表达式树
对象拼接到由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);
}
}
//需要在typeof()中引用显式命名的类型
私有类ResultType
{
公共字符串子类别名称{get;set;}
public int ProductNumber{get;set;}|
}
私有静态void DoSomethingWithExpression(
表达式(myExpression)
{
var productParam=表达式参数(产品类型),“产品”);
var groupExpr=(表达式)Expression.Lambda(
Expression.MemberInit(
Expression.New(typeof(ResultType)),
表达式绑定(
typeof(ResultType).GetProperty(“子类别名称”),
Expression.Invoke(myExpression,productParam)),
表达式绑定(
typeof(ResultType).GetProperty(“ProductNumber”),
Expression.Property(productParam,“ProductNumber”)),
productParam);
使用(AdventureWorksDataContext db=new AdventureWorksDataContext())
{
var result=db.Products.GroupBy(groupExpr);
}
}
你错过了他从Func
转到Expression
的最初原因-他希望这在LINQ到SQL的上下文中工作,这不允许在查询中随机调用函数(或委托)。你击败了Pavel,但他的答案对我来说更清楚+谢谢你的帮助。谢谢我同意帕维尔的答案更好。我的代码基于为构造匿名类型而生成的表达式;MemberInit是命名类型所需的。很好!不过,最后一行不是为我编译的,因为结果被分配给了。“无法从用法推断方法…的类型参数。”我是否遗漏了什么?应将Expression.Lambda
中的返回值转换为Expression
。非常好!这比我想象的要复杂得多。我以前从未做过这样的表达,所以我将学习这段代码以确保我完全理解发生了什么。谢谢是的——学习如何手动构建表达式树永远不会太早;有很多常见的场景都需要它…看起来你也可以说Expression.Lambda(…而不是casting。
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);
// ...
}
}
// 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);
}
}