2017-07-05 7 views
2

は、2つの発現ツリーを考えてみましょう:式ツリーは - 代替表現

Expression<Func<float, float, float>> f1 = (x, y) => x + y; 
Expression<Func<float, float>> f2 = x => x * x; 

私はf1の2番目のパラメータとして表現f2に置き換えて、次の式を取得する:

Expression<Func<float, float, float>> f3 = (x, y) => x + y * y; 

最も簡単な方法がありますExpression.LambdaExpression.Invokeを使用すると、結果は次のようになります

しかし、これはinvoke/lambdaを適切に処理できないORMの制限のために私にとって受け入れられないものです。

式ツリーを完全に横断することなく式を構築することは可能ですか?私のニーズを満たす実際の例はhereですが、もっと簡単な解決法が必要です。

+0

のフルトラバーサルなし表現木 - いいえ。基本的には、 'ExpressionVisitor'で実装されているパラメータ置換えが必要です。 –

答えて

2

両方の式を完全にトラバーサルすることはできません。幸い、ExpressionVisitorは本当に簡単フルトラバーサルを作る:

class ReplaceParameter : ExpressionVisitor { 
    private readonly Expression replacement; 
    private readonly ParameterExpression parameter; 
    public ReplaceParameter(
     ParameterExpression parameter 
    , Expression replacement 
    ) { 
     this.replacement = replacement; 
     this.parameter = parameter; 
    } 
    protected override Expression VisitParameter(ParameterExpression node) { 
     return node == parameter ? replacement : node; 
    } 
} 

使用このビジターは二回交換を完了するために:

Expression<Func<float,float,float>> f1 = (x, y) => x + y; 
Expression<Func<float,float>> f2 = x => x * x; 
var pX = f2.Parameters[0]; 
var pY = f1.Parameters[1]; 
var replacerF2 = new ReplaceParameter(pX, pY); 
var replacerF1 = new ReplaceParameter(pY, replacerF2.Visit(f2.Body)); 
var modifiedF1 = Expression.Lambda(
    replacerF1.Visit(f1.Body) 
, f1.Parameters 
); 
Console.WriteLine(modifiedF1); 

上記プリント

(x, y) => (x + (y * y)) 

Demo.