2010-08-20 64 views
2

如果我有一個規範中定義爲表達式如下:規格圖案 - 創建使用的lambda(C#)化合物規格

public Expression<Func<Foo, bool>> IsSuperhuman = 
    x => x.CanFly && x.HasXRayVision; 

我想要定義另一個規範「IsSuperheroine」與邏輯「是超人和是女性',我如何重新使用新規範中的現有規範?

+1

你爲什麼要使用表達式爲這個?看起來代表就夠了。 – leppie 2010-08-20 10:36:01

+3

因爲你不能在IQueryable的Where子句中使用簡單的委託,就像我昨天發現的那樣。 – David 2010-08-20 11:29:06

回答

1

你在LinqKit簽出predicate builder嗎?它通過讓你和/或表達式一起建立表達式。

+0

我相信NCommon有類似的東西,但我現在正在甩掉我自己的東西。 – David 2010-08-20 11:21:06

+0

我是絕對的扳手。如果我能正確地閱讀你的鏈接,它可以節省我大量的工作。你是上帝! – David 2011-03-17 10:37:27

1

這裏有一個辦法做到這一點:

Expression<Func<Foo, bool>> IsSuperhuman = x => x.CanFly && x.HasXRayVision; 

Expression<Func<Foo, bool>> IsSuperheroine = AndAlso(IsSuperhuman, x => x.IsFemale); 

... 

public static Expression<Func<T, TResult>> AndAlso<T, TResult>(Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2) 
{ 
    var arg = Expression.Parameter(typeof(T), expr1.Parameters[0].Name); 
    var andExpr = Expression.AndAlso(
     ReplaceParameter(expr1.Body, expr1.Parameters[0], arg), 
     ReplaceParameter(expr2.Body, expr2.Parameters[0], arg)); 
    return Expression.Lambda<Func<T, TResult>>(andExpr, arg); 
} 

public static Expression ReplaceParameter(Expression expr, ParameterExpression oldParam, ParameterExpression newParam) 
{ 
    return new ReplaceParameterVisitor(oldParam, newParam).Visit(expr); 
} 

internal class ReplaceParameterVisitor : ExpressionVisitor 
{ 
    private ParameterExpression _oldParam; 
    private ParameterExpression _newParam; 

    public ReplaceParameterVisitor(ParameterExpression oldParam, ParameterExpression newParam) 
    { 
     _oldParam = oldParam; 
     _newParam = newParam; 
    } 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     if (node == _oldParam) 
      return _newParam; 
     return node; 
    } 
} 

這可能是不這樣做最簡單的方法,但它的作品...

+0

謝謝!我會直言不諱地說,直到我經歷了Expressions API的這段時間,並找出了它的意義。 – David 2010-08-25 14:07:08