要在Select()查询中使用的Lambda表达式

时间:2010-04-27 08:31:40

标签: c# lambda expression-trees

我正在尝试构建一个lambda表达式,包含两个赋值(如下图所示),然后我可以传递给Queryable.Select()方法。

我正在尝试将字符串变量传递给方法,然后使用该变量来构建lambda表达式,以便我可以在LINQ Select查询中使用它。

我的理由是我有一个包含许多列名的SQL Server数据源,我正在创建一个图表应用程序,允许用户通过输入列名来选择他们想要的实际数据列。在我的图表的y轴上查看,x轴始终是DateTime。因此,他们基本上可以根据DateTime值选择他们绘制的数据(它是数据仓库类型的应用程序)。

例如,我有一个类来存储检索到的数据,因此用作以下的图表来源:

public class AnalysisChartSource
{
    public DateTime Invoicedate { get; set; }
    public Decimal yValue { get; set; }
}

我(纯粹是实验性的)使用String值为Where子句构建了一个表达式树,并且工作正常:

public void GetData(String yAxis)
{
    using (DataClasses1DataContext db = new DataClasses1DataContext())
    {
        var data = this.FunctionOne().AsQueryable<AnalysisChartSource>();
        //just to get some temp data in....

        ParameterExpression pe = Expression.Parameter(typeof(AnalysisChartSource), "p");
        Expression left = Expression.MakeMemberAccess(pe,
                                                typeof(AnalysisChartSource).GetProperty(yAxis));
        Expression right = Expression.Constant((Decimal)16);
        Expression e2 = Expression.LessThan(left, right);
        Expression expNew = Expression.New(typeof(AnalysisChartSource));

        LambdaExpression le = Expression.Lambda(left, pe);

        MethodCallExpression whereCall = Expression.Call(
            typeof(Queryable), "Where", new Type[] { data.ElementType },
            data.Expression,
            Expression.Lambda<Func<AnalysisChartSource, bool>>(e2, new ParameterExpression[] { pe }));
    }
}

然而......我已经为Select语句尝试了类似的方法,但是无法使它工作,因为我需要Select()来填充AnalysisChartSource类的X和Y值,如下所示:

.Select(c => new AnalysisChartSource 
{ Invoicedate = c.Invoicedate, yValue = c.yValue}).AsEnumerable();

我怎样才能构建这样一个表达树......或者......可能更重要的是......我有一个更容易错过的方法吗?

1 个答案:

答案 0 :(得分:15)

我发现解决如何构建表达式树的最佳方法是查看C#编译器的功能。所以这是一个完整的程序:

using System;
using System.Linq.Expressions;

public class Foo
{
    public int X { get; set; }
    public int Y { get; set; }
}

class Test
{
    static void Main()
    {
        Expression<Func<int, Foo>> builder = 
            z => new Foo { X = z, Y = z };
    }
}

编译,在Reflector中打开结果并将优化设置为.NET 2.0。您最终会为Main方法生成此代码:

ParameterExpression expression2;
Expression<Func<int, Foo>> expression = 
  Expression.Lambda<Func<int, Foo>>(
    Expression.MemberInit(
      Expression.New((ConstructorInfo) methodof(Foo..ctor), new Expression[0]),
      new MemberBinding[] { Expression.Bind((MethodInfo) methodof(Foo.set_X),
                           expression2 = Expression.Parameter(typeof(int), "z")),
                           Expression.Bind((MethodInfo) methodof(Foo.set_Y), 
                                            expression2) }
    ),
    new ParameterExpression[] { expression2 });

基本上,我认为Expression.MemberInit就是您所追求的目标。