2013-05-29 50 views
13

假設我有類似從BinaryExpression以表達<Func鍵<T, bool>>

Expression<Func<SomeType, DateTime>> left = x => x.SomeDateProperty; 
Expression<Func<SomeType, DateTime>> right = x => dateTimeConstant; 
var binaryExpression = Expression.GreaterThan(left, right); 
Expression<Func<SomeType, bool>> predicate = 
          x => x.SomeDateProperty> dateTimeConstant; 

1)我怎樣才能用的東西代替最後一行的分配的右手使用binaryExpression呢? var predicate = x => binaryExpression;不起作用。

2)right始終是一個常數,不一定是DateTime.Now。它可以是一些簡單Expression類型?例如,它不依賴於SomeType,它只是一個常量。

3)如果我有GreaterThan作爲string,有沒有辦法從這個字符串獲取Expression中同名的方法?一般來說,如果比較方法的名稱爲string,那麼如何才能從字符串中實際調用Expression類中的同名方法?

它必須與LINQ to Entities一起工作,如果它很重要的話。

+0

您可以使用ExpressionVisitor類更改表達式樹。 – Steven

回答

13

1和2:您需要手動構建表達式樹來執行此操作,編譯器無法提供幫助,因爲它僅構造代表完整功能的現成表達式。當你想逐個構建函數時,這沒有用。

下面是打造你想要表達一個簡單的方法:

var argument = Expression.Parameter(typeof(SomeType)); 
var left = Expression.Property(argument, "SomeDateProperty"); 
var right = Expression.Constant(DateTime.Now); 

var predicate = Expression.Lambda<Func<SomeType, bool>>(
    Expression.GreaterThan(left, right), 
    new[] { argument } 
); 

您可以

var param = new SomeType { 
    SomeDateProperty = DateTime.Now.Add(TimeSpan.FromHours(-1)) 
}; 

Console.WriteLine(predicate.Compile()(param)); // "False" 

3藉此試駕:由於可能的選擇,在所有的可能性數你的二元謂詞將會很小,你可以用字典來做到這一點:

var wordToExpression = 
    new Dictionary<string, Func<Expression, Expression, BinaryExpression>> 
{ 
    { "GreaterThan", Expression.GreaterThan }, 
    // etc 
}; 

然後,代替在第一個代碼段中對Expression.GreaterThan進行硬編碼,您將執行類似wordToExpression["GreaterThan"](left, right)的操作。

當然這也可以用反射的標準方式來完成。

7

當您使用GreaterThan時,您需要指定表達式機構,而不是lambda本身。不幸的是,還有一個併發症:中的兩個表達式不一樣。

在這種特別情況下,你勉強能逃脫這一點,因爲第二個表達式不使用x

左右;您的「1」和「2」應回答:

var binaryExpression = Expression.GreaterThan(left.Body, right.Body); 
    var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression, 
     left.Parameters); 

然而,在一般情況下解決這個問題,你必須上表達的改寫,修復行動的參數:

var binaryExpression = Expression.GreaterThan(left.Body, 
    new SwapVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body)); 
var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression, 
    left.Parameters); 

有:

public class SwapVisitor : ExpressionVisitor 
{ 
    private readonly Expression from, to; 
    public SwapVisitor(Expression from, Expression to) 
    { 
     this.from = from; 
     this.to = to; 
    } 
    public override Expression Visit(Expression node) 
    { 
     return node == from ? to : base.Visit(node); 
    } 
} 

爲貴 「3」;這沒有什麼內在的;您可以使用反射:

string method = "GreaterThan"; 

var op = typeof(Expression).GetMethod(method, 
    BindingFlags.Public | BindingFlags.Static, 
    null, new[] { typeof(Expression), typeof(Expression) }, null); 

var rightBody = new SwapVisitor(right.Parameters[0], 
    left.Parameters[0]).Visit(right.Body); 
var exp = (Expression)op.Invoke(null, new object[] { left.Body, rightBody }); 

var lambda = Expression.Lambda<Func<SomeType, bool>>(exp, left.Parameters); 
相關問題