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

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

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

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

 var productParameter = Expression.Parameter(typeof(Product), "product"); // The Problem var groupExpression = Expression.Lambda<Func>( 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是不正确的(参见exception的代码注释),但我不确定我应该怎么做。 我以为我说的是“从product.Blarg获取表达式,执行它,并返回字符串结果。” 我想那并不是我在那里说的那些。 我还在试图找出表达树。 知道我怎么能把它拉下来?

当您调用Expression.Invoke ,第一个参数必须是现有的LambdaExpression – 它不能是LambdaExpressionExpression 。 或者换句话说:它不会每行评估Product.Blarg 每次都使用不同的子表达式。

相反,您将首先检索此lambda,如果您只是通过名称知道它,可能会将其设置为static并通过reflection访问它:

 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> 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>( 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(); 

这与Marc的代码相同。

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