2011-03-25 37 views
11

我正在嘗試基於規範對象動態構建表達式。替換表達式正文中的參數名稱

我已經創建了一個擁有私人表達,像這樣的ExpressionHelper類:

private Expression<Func<T, bool>> expression; 

public ExpressionHelper() 
{ 
    expression = (Expression<Func<T, bool>>)(a => true); 
} 

然後一些簡單的方法如下:

public void And(Expression<Func<T,bool>> exp); 

我與的身體掙扎和方法。我基本上想要撕掉exp的身體,將所有參數替換爲expression中的所有參數,然後將其附加到expression身體的末端,以及AndAlso。

我已經做到了這一點:

var newBody = Expression.And(expression.Body,exp.Body); 

expression = expression.Update(newBody, expression.Parameters); 

但是,這與我的表達最終看起來像這樣:

{ a => e.IsActive && e.IsManaged } 

有沒有一種簡單的方法來做到這一點?或者我怎樣才能將這些電子設備拆除並用一個電子設備取而代之?

回答

20

最簡單的辦法就是在這裏Expression.Invoke,例如:

public static Expression<Func<T, bool>> AndAlso<T>(
    Expression<Func<T, bool>> x, Expression<Func<T, bool>> y) 
{ 
    return Expression.Lambda<Func<T, bool>>(
     Expression.AndAlso(x.Body, Expression.Invoke(y, x.Parameters)), 
     x.Parameters); 
} 

這工作得很好LINQ到對象和LINQ到SQL,但不支持EF。對於EF,你需要使用訪問者來重寫樹,不幸的是。

使用代碼:Combining two lambda expressions in c#

public static Expression<Func<T, bool>> AndAlso<T>(
    Expression<Func<T, bool>> x, Expression<Func<T, bool>> y) 
{ 
    var newY = new ExpressionRewriter().Subst(y.Parameters[0], x.Parameters[0]).Inline().Apply(y.Body); 

    return Expression.Lambda<Func<T, bool>>(
     Expression.AndAlso(x.Body, newY), 
     x.Parameters); 
} 

還是在.NET 4.0中,使用ExpressionVisitor

class ParameterVisitor : ExpressionVisitor 
{ 
    private readonly ReadOnlyCollection<ParameterExpression> from, to; 
    public ParameterVisitor(
     ReadOnlyCollection<ParameterExpression> from, 
     ReadOnlyCollection<ParameterExpression> to) 
    { 
     if(from == null) throw new ArgumentNullException("from"); 
     if(to == null) throw new ArgumentNullException("to"); 
     if(from.Count != to.Count) throw new InvalidOperationException(
      "Parameter lengths must match"); 
     this.from = from; 
     this.to = to; 
    } 
    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     for (int i = 0; i < from.Count; i++) 
     { 
      if (node == from[i]) return to[i]; 
     } 
     return node; 
    } 
} 
public static Expression<Func<T, bool>> AndAlso<T>(
     Expression<Func<T, bool>> x, Expression<Func<T, bool>> y) 
{ 
    var newY = new ParameterVisitor(y.Parameters, x.Parameters) 
       .VisitAndConvert(y.Body, "AndAlso"); 
    return Expression.Lambda<Func<T, bool>>(
     Expression.AndAlso(x.Body, newY), 
     x.Parameters); 
} 
+0

該死,剛剛調用內存的工作和EF被測試時發生這種情況。謝謝。 – 2011-03-25 11:00:39

+0

@robert IIRC調用不適用於EF,因此您需要使用第二個版本 – 2011-03-25 11:02:56

+0

您的方法可行,但現在我的代碼庫中有令人驚訝的複雜且未經測試的ReWriter。 :(看到它看起來有多聰明,我會保留它,直到我明白它! – 2011-03-25 11:23:53