Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Jul 17th, 2012  |  syntax: None  |  size: 2.89 KB  |  hits: 25  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. Replace parameter in lambda expression
  2. public class Foo
  3. {
  4.     public int a { get; set; }
  5.     public int b { get; set; }
  6. }
  7.  
  8. private void Test()
  9. {
  10.     List<Foo> foos = new List<Foo>();
  11.     foos.Add(new Foo());
  12.     foos.Add(new Foo());
  13.     Expression<Func<Foo, int>> exp0 = f => f.a * f.b;
  14.     Expression<Func<int>> exp1 = () => foos[0].a * foos[0].b;
  15.     Expression<Func<int>> exp2 = () => foos[1].a * foos[1].b;
  16. }
  17.        
  18. Foo foo = new Foo();
  19. Expression<Func<int>> exp = () => foo.a * foo.a + foo.b;
  20. string result1 = GetResult(exp); // gets "v_001 * v_001 + v_002"
  21.  
  22. List<Foo> foes = new List<Foo>();
  23. foes.Add(new Foo());
  24. foes.Add(new Foo());
  25. Expression<Func<int>> exp2 = () => foes.Sum(f => f.a * f.a + f.b);
  26. string result2 = GetResult(exp2); // should get "(v_001 * v_001 + v_002) + (v_003 * v_003 + v_004)"
  27.        
  28. public static class ParameterReplacer
  29. {
  30.     // Produces an expression identical to 'expression'
  31.     // except with 'source' parameter replaced with 'target' expression.    
  32.     public static Expression<TOutput> Replace<TInput, TOutput>
  33.                     (Expression<TInput> expression,
  34.                     ParameterExpression source,
  35.                     Expression target)
  36.     {
  37.         return new ParameterReplacerVisitor<TOutput>(source, target)
  38.                     .VisitAndConvert(expression);
  39.     }
  40.  
  41.     private class ParameterReplacerVisitor<TOutput> : ExpressionVisitor
  42.     {
  43.         private ParameterExpression _source;
  44.         private Expression _target;
  45.  
  46.         public ParameterReplacerVisitor
  47.                 (ParameterExpression source, Expression target)
  48.         {
  49.             _source = source;
  50.             _target = target;
  51.         }
  52.  
  53.         internal Expression<TOutput> VisitAndConvert<T>(Expression<T> root)
  54.         {
  55.             return (Expression<TOutput>)VisitLambda(root);
  56.         }
  57.  
  58.         protected override Expression VisitLambda<T>(Expression<T> node)
  59.         {
  60.             // Leave all parameters alone except the one we want to replace.
  61.             var parameters = node.Parameters
  62.                                  .Where(p => p != _source);
  63.  
  64.             return Expression.Lambda<TOutput>(Visit(node.Body), parameters);
  65.         }
  66.  
  67.         protected override Expression VisitParameter(ParameterExpression node)
  68.         {
  69.             // Replace the source with the target, visit other params as usual.
  70.             return node == _source ? _target : base.VisitParameter(node);
  71.         }
  72.     }
  73. }
  74.        
  75. var zeroIndexIndexer = Expression.MakeIndex
  76.         (Expression.Constant(foos),
  77.          typeof(List<Foo>).GetProperty("Item"),
  78.          new[] { Expression.Constant(0) });
  79.  
  80.  
  81. // .ToString() of the below looks like the following:
  82. //  () =>    (value(System.Collections.Generic.List`1[App.Foo]).Item[0].a
  83. //         *  value(System.Collections.Generic.List`1[App.Foo]).Item[0].b)
  84. var exp1Clone = ParameterReplacer.Replace<Func<Foo, int>, Func<int>>
  85.                   (exp0, exp0.Parameters.Single(), zeroIndexIndexer);