从包含参数的成员表达式中提取值

本文关键字:提取 表达式 成员 包含 参数 | 更新日期: 2023-09-27 18:33:09

如何从成员表达式中提取值,其中成员表达式中的表达式不是常量,而是参数表达式。

我正在为我们公司构建一个小型的Linq to MDX ORM。

在我的生成器模板中,在数据库中找到的每个维度都是一个类,在每个维度中,都有为该维度找到的Attribute属性。 生成所有维度类后,将生成一个更高级别Cube类,其中包含维度作为属性以及该多维数据集的度量值。 生成所有多维数据集类后,将生成一个最终类,其中包含作为Cube<MyCube>属性生成的多维数据集类,其中Cube<>是我的IQueryable类型。下面是一个示例。

//Generated cs file example:
public partial MyDatabase : CubeBase
{
    //Some base implementation goes here        
    public Cube<FooCube> FooCube { get { return new Cube<FirstCube>(new Provider("connection string"); } }
    //Any other cubes would follow here that were found on this database.
} 
//A calendar dimension
public class FooCube_CalendarDimension
{
    public Attribute WeekEnding { get { return new Attribute("[Calendar].[Week Ending]"); } }
    public Attribute Month { get { return new Attribute("[Calendar].[Month]"); } }
    public Attribute Year { get { return new Attribute("[Calendar].[Year]"); } }
}
//The "FooCube" 
public partial class FooCube
{
    //List Dimensions
    public FooCube_Calendar_Dimension Calendar { get { return new FooCube_Calendar_Dimension(); }     }
    //Other dimensions here
    [Measure]
    public string RetailDollars { get { return "[Retail Dollars]"; } }
    // Other measures here
}

现在,下面是一个用于查询多维数据集的非常基本的 linq 查询示例:

//using MyDatabase = db
var mdx = from cube in db.FooCube
          where cube.Calendar.Year == "2014"
          select new
          {
              Month = cube.Calendar.Month.Children
              Dollars = cube.RetailDollars
          }

例如,我正在尝试从多维数据集获取值。Calendar.Month.Children,它来自 Attribute 对象,该对象是 FooCube_Calendar_Demsion 类的属性,它本身就是"FooCube"类中的一个属性。

我尝试

了访问成员表达式的值的答案,但是当它尝试编译lambda表达式时,我收到错误"未引用'cube'参数"。它传递给属性类构造函数的值存储在属性中,这就是我要访问的值(其中一个(。

从包含参数的成员表达式中提取值

基本上,你不能。 至少,不是以任何明智的方式。 目前,您所拥有的只是一个查询。 您实际上没有对象的集合,您只有有关创建这些对象需要执行的操作的信息。 查询提供程序的工作是,您当前正在编写实际生成查询定义的对象并返回它们。

您已经设计了程序,以便创建对象的查询提供程序需要已经创建对象,以便正确生成查询。 不可能已经拥有尚未生成的查询定义的对象。 您已经为自己创建了一个循环依赖项。

请务必

提供在查询本身创建的对象以外的其他位置生成查询所需的信息。 通常,这是通过属性上的属性完成的,或者通过将查询基于有关类型本身的其他现有 C# 元数据来完成的。 此类型数据存在,可供查询提供程序访问,而无需您负责创建的对象的任何实际实例

我添加这个答案是因为我找到了两种提取我想要的值的方法。我要感谢Servey的回答,因为他确实是正确的,因为我写了我的代码,所以没有以任何明智的方式这样做。

我发现有两种方法可以做到这一点。

    将泛型
  1. 转换器类与泛型参数一起使用,泛型参数是我的 lambda 表达式所需的参数的类类型,然后将该泛型参数用作Func<object, T> delgate上的输入参数。 这是最好和最快的方法,因为在运行时没有动态操作。

var lambda = Expression.Lambda<Func<object, T>>(//Expressions here);

  1. 我发现的第二种方法较慢,因为它涉及Delegate.DynamicInvoke()方法,但它确实有效。

    var lambda = Expression.Lambda(member, (ParameterExpression)member.Expression); var d = lambda.Compile(); return d.DynamicInvoke(member.Expression.Type.GetConstructors()[0].Invoke(new object[0]));

这将获取对象的值,但由于动态调用而代价高昂。