从属性中检索表达式并将其添加到表达式树中
我试图简化这个例子,因为我正在使用的实际代码更复杂。 所以虽然这个例子看起来很傻,但请耐心等待。 假设我正在使用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
– 它不能是LambdaExpression
的Expression
。 或者换句话说:它不会每行评估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
已经正确,没有理由“重新调用”它。