2012-06-22 10 views
9

をパラメータに置き換えます。は、このコードを考慮すると、ラムダ式で

public class Foo 
{ 
    public int a { get; set; } 
    public int b { get; set; } 
} 

private void Test() 
{ 
    List<Foo> foos = new List<Foo>(); 
    foos.Add(new Foo()); 
    foos.Add(new Foo()); 
    Expression<Func<Foo, int>> exp0 = f => f.a * f.b; 
    Expression<Func<int>> exp1 =() => foos[0].a * foos[0].b; 
    Expression<Func<int>> exp2 =() => foos[1].a * foos[1].b; 
} 

はどのようにexp0を取り、exp1exp2と同一の二つの式に変換することができます。各Fooexp0foosに評価するのではなく、2つの新しい式が得られることに注意してください。

[更新]

基本的に、私はこれらの列挙ので、このような列挙内の項目ごとに1式にSumとしてLinq拡張メソッドに渡された式を展開または「フラット化」することができるようになるでしょう私はすでにパラメータを取っていない式を読み込んで、別の言語に変換するコードを持っているからです。

:私は(この場合には abは、この属性を持っているでしょう)、特定の属性を持つプロパティへの参照として MetadataTokenを使用し、別の言語の変数にC#のプロパティを関連付ける辞書でそれを使用してい

次のようにオリジナルの表現を操作するパラメータ代用表現-ビジターを書く:

Foo foo = new Foo(); 
Expression<Func<int>> exp =() => foo.a * foo.a + foo.b; 
string result1 = GetResult(exp); // gets "v_001 * v_001 + v_002" 

List<Foo> foes = new List<Foo>(); 
foes.Add(new Foo()); 
foes.Add(new Foo()); 
Expression<Func<int>> exp2 =() => foes.Sum(f => f.a * f.a + f.b); 
string result2 = GetResult(exp2); // should get "(v_001 * v_001 + v_002) + (v_003 * v_003 + v_004)" 
+0

あなたが私たちに与えることはできますが、どのようにこれを使用し、出力はどのようになるのかの例は? –

+0

も参照してくださいhttp://stackoverflow.com/questions/5631070/currying-expressions-in-c-sharp – AakashM

答えて

15

私は、このようにそれを行うだろう

  1. ラムダシグネチャから完全には必要としないパラメータを削除します。
  2. パラメータのすべての用途を、目的のインデクサ式に置き換えます。

ここで私は別の質問で私のearlier answerに基づいて手早く迅速かつ汚いサンプルです:あなたのシナリオの

public static class ParameterReplacer 
{ 
    // Produces an expression identical to 'expression' 
    // except with 'source' parameter replaced with 'target' expression.  
    public static Expression<TOutput> Replace<TInput, TOutput> 
        (Expression<TInput> expression, 
        ParameterExpression source, 
        Expression target) 
    { 
     return new ParameterReplacerVisitor<TOutput>(source, target) 
        .VisitAndConvert(expression); 
    } 

    private class ParameterReplacerVisitor<TOutput> : ExpressionVisitor 
    { 
     private ParameterExpression _source; 
     private Expression _target; 

     public ParameterReplacerVisitor 
       (ParameterExpression source, Expression target) 
     { 
      _source = source; 
      _target = target; 
     } 

     internal Expression<TOutput> VisitAndConvert<T>(Expression<T> root) 
     { 
      return (Expression<TOutput>)VisitLambda(root); 
     } 

     protected override Expression VisitLambda<T>(Expression<T> node) 
     { 
      // Leave all parameters alone except the one we want to replace. 
      var parameters = node.Parameters 
           .Where(p => p != _source); 

      return Expression.Lambda<TOutput>(Visit(node.Body), parameters); 
     } 

     protected override Expression VisitParameter(ParameterExpression node) 
     { 
      // Replace the source with the target, visit other params as usual. 
      return node == _source ? _target : base.VisitParameter(node); 
     } 
    } 
} 

を使用(テスト):

var zeroIndexIndexer = Expression.MakeIndex 
     (Expression.Constant(foos), 
     typeof(List<Foo>).GetProperty("Item"), 
     new[] { Expression.Constant(0) }); 


// .ToString() of the below looks like the following: 
// () => (value(System.Collections.Generic.List`1[App.Foo]).Item[0].a 
//   * value(System.Collections.Generic.List`1[App.Foo]).Item[0].b) 
var exp1Clone = ParameterReplacer.Replace<Func<Foo, int>, Func<int>> 
        (exp0, exp0.Parameters.Single(), zeroIndexIndexer); 
+1

入れ子のラムダについては、Expression.Lambda (。 ..)。いずれの場合も、型パラメータのバージョンは不要です。 – HappyNomad

関連する問題