替换lambda表达式中的参数

考虑这段代码:

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

如何将exp0转换为与exp1exp2相同的两个表达式。 请注意,我不想仅为exp0中的每个Foo计算foos ,而是获得两个新表达式。

[更新]

基本上,我希望能够将传递给Linq扩展方法(如Sum的表达式扩展或“展平”到枚举中每个项目的一个表达式,因为这些枚举将是静态的,并且因为我已经有代码来读取表达式拿参数(然后把它们变成另一种语言)。

我使用MetadataToken作为对具有特定属性的属性的引用(在这种情况下ab将具有此属性)并将其与将C#属性与另一种语言的变量相关联的字典一起使用:

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

我会这样做:

编写一个参数 – replacer表达式 – 访问者,操作原始表达式如下:

  1. 从lambda签名中删除完全不需要的参数。
  2. 用所需的索引器表达式替换参数的所有用法。

这是一个快速而肮脏的样本,我根据我之前在另一个问题上的回答掀起了一个问题:

 public static class ParameterReplacer { // Produces an expression identical to 'expression' // except with 'source' parameter replaced with 'target' expression. public static Expression Replace (Expression expression, ParameterExpression source, Expression target) { return new ParameterReplacerVisitor(source, target) .VisitAndConvert(expression); } private class ParameterReplacerVisitor : ExpressionVisitor { private ParameterExpression _source; private Expression _target; public ParameterReplacerVisitor (ParameterExpression source, Expression target) { _source = source; _target = target; } internal Expression VisitAndConvert(Expression root) { return (Expression)VisitLambda(root); } protected override Expression VisitLambda(Expression node) { // Leave all parameters alone except the one we want to replace. var parameters = node.Parameters .Where(p => p != _source); return Expression.Lambda(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).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> (exp0, exp0.Parameters.Single(), zeroIndexIndexer);