2010-04-27 132 views
8

我想構建一個lambda表達式,其中包含兩個賦值(如下面所示),然後可以傳遞給Queryable.Select()方法。在Select()查詢中使用的Lambda表達式

我想將一個字符串變量傳遞給一個方法,然後使用該變量來構建lambda表達式,以便我可以在LINQ Select查詢中使用它。

我的理由是,我有一個SQL Server數據源與許多列名稱,我正在創建一個圖表應用程序,允許用戶選擇,例如通過鍵入列名稱,他們想要的數據的實際列在我的圖表的y軸上查看,x軸始終是DateTime。因此,他們基本上可以根據DateTime值(它是一個數據倉庫類型的應用程序)選擇哪些數據。

我已經,例如,存儲在檢索到的數據,並且因此一類使用盡可能的圖表源:

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

我已經使用(純粹experimentaly)構建的表達式樹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語句類似的辦法,但就是無法得到它的工作,因爲我需要選擇()來填充X和AnalysisChartSource類的Y值如下所示:

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

我怎麼可以建立這樣一個表達樹......或者......可能更重要的是......有一種更簡單的方法,我完全錯過了嗎?

回答

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。你最終得到的主要方法生成的代碼:

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是你追求的。

+0

喬恩很棒的主意。我會給你100票的解決方案! :-) – gsharp 2010-04-27 08:46:40

+0

喬恩,輝煌!非常感謝!我同意gsharp,一個好主意! - 反射器是我的新朋友:-)再次感謝 – jameschinnock 2010-04-27 09:22:23

+0

@GSharp,我會幫你:+1。 – Steven 2010-04-27 10:21:49