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

标签 c# .net linq-to-sql expression-trees

我已尝试简化此示例,因为我正在使用的实际代码更为复杂。因此,尽管这个示例可能看起来很愚蠢,但请耐心等待。假设我正在使用 AdventureWorks 数据库,我决定将一个名为 Blarg 的属性添加到 Product 表,该表返回一个包含我想要的代码的表达式在几个地方使用:

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

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

var productParameter = Expression.Parameter(typeof(Product), "product");

// The Problem
var groupExpression = Expression.Lambda<Func<Product, string>>(
    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 是不正确的(请参阅异常的代码注释),但我不确定我应该怎么做。我以为我说的是“从 product.Blarg 中获取表达式,执行它,然后返回字符串结果。”不过,我想那不是我真正要说的。我仍在尝试找出表达式树。知道如何实现吗?

最佳答案

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

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

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<Func<Product, string>> 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<Func<Product, string>>(
            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();
    }
}

关于c# - 从属性中检索表达式并将其添加到表达式树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1599999/

相关文章:

C# GetMethod 不返回父方法

c# - 如何向当前服务器请求资源(相对路径)?

c# - 实例字段的初始化与局部变量

c# - 创建数据上下文对象的更短方法?

linq - 在 Entity Framework 的 LINQ 中使用 "NOT IN"从两个表中选择

c# - 为什么这些任务开始延迟?

c# - 使用 WCF 的 REST 服务 - 可选的查询字符串参数?

c# - sqlserver 连接字符串中的用户名、密码和其他参数

c# - 等效的 LINQ to SQL 代码

C# 我可以将字典中对象的属性显示为 ListControl.DisplayMember 吗?