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

时间:2014-12-03 17:38:28

标签: c# linq expression mdx expression-trees

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

我正在为我们公司建立一个小型的Linq到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
          }

例如,我正在尝试从cube.Calendar.Month.Children中获取值,该值来自属性对象,该对象是FooCube_Calendar_Demsion类的属性,它本身就是“FooCube”类中的属性

我尝试了Access the value of a member expression的答案,但是我收到错误,“当试图编译lambda表达式时,'''参数未被引用”。它传递给属性类构造函数的值存储在一个属性中,这就是我想要访问的值(其中一个)。

2 个答案:

答案 0 :(得分:1)

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

您已经设计了自己的程序,以便创建对象的查询提供程序需要已经创建了对象,才能正确构建查询。已经有了尚未构建的查询定义的对象,这是不可能的。你已经为自己创造了循环依赖。

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

答案 1 :(得分:-1)

我正在添加这个答案,因为我发现了两种提取我想要的值的方法。我想感谢Servey的回答,因为他确实没有以任何合理的方式做到这一点,因为我编写了代码。

我发现了两种解决方法。

  1. 使用具有泛型参数的通用转换器类,该参数是我的lambda表达式所需的参数的类类型,然后将该泛型参数用作Func<object, T> delgate上的输入参数。这是最好和最快的方法,因为在运行时没有动态操作。
  2. 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]));

    2. 这将获得对象的值,但由于动态调用而成本很高。