【问题标题】:Lambda Expression to be used in Select() query要在 Select() 查询中使用的 Lambda 表达式
【发布时间】:2010-04-27 08:31:40
【问题描述】:

我正在尝试构建一个 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; }
}

我已经(纯粹是实验性的)使用字符串值为 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();

我到底如何才能构建这样一个表达式树......或者......可能更重要......有没有更简单的方法我完全错过了?

【问题讨论】:

    标签: c# lambda expression-trees


    【解决方案1】:

    我发现了解如何构建表达式树的最佳方法是查看 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 是您所追求的。

    【讨论】:

    • 乔恩好主意。我会给你 100 票赞成这个解决方案! :-)
    • 乔恩,太棒了!!非常感谢!我同意 gsharp,一个好主意! - Reflector 是我的新朋友 :-) 再次感谢
    • @GSharp,我会帮你的:+1。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多