更改LambdaExpression中的参数名称仅用于显示

假设我有一个这样的表达式:

Expression<Predicate> exp 

如果我分配以下表达式:

 a => a.First() != 0 

然后我调用exp.ToString()我将获得我传递的表达式,这是非常好的,但是,假设我们想要用其他东西更改我们用于’a’的名称,我们该怎么办? 字符串替换在所有情况下都不会起作用(它在上面的示例中起作用,但是如果参数例如被称为’i’怎么办?)是否可以只更改参数名称,运行时间,而不影响表达式语义?

更新 @PhilKlein工作得很好,但需要框架4.但是如果我们需要定位框架3.5,我们可以使用Matt Warren的ExpressionVisitor类,只需修改从protected到public的Visit方法。

它快速而又脏,但假设您使用的是.NET 4.0,则可以创建以下内容:

 public class PredicateRewriter { public static Expression> Rewrite(Expression> exp, string newParamName) { var param = Expression.Parameter(exp.Parameters[0].Type, newParamName); var newExpression = new PredicateRewriterVisitor(param).Visit(exp); return (Expression>) newExpression; } private class PredicateRewriterVisitor : ExpressionVisitor { private readonly ParameterExpression _parameterExpression; public PredicateRewriterVisitor(ParameterExpression parameterExpression) { _parameterExpression = parameterExpression; } protected override Expression VisitParameter(ParameterExpression node) { return _parameterExpression; } } } 

然后使用如下:

 var newExp = PredicateRewriter.Rewrite(exp, "b"); newExp.ToString(); // returns "b => (b.First() == 0)" in your case 

表达式是不可变的,因此,您无法修改它们,您需要构造新的树。

在.NET 4.0中,有一个可以帮助您的类,请参阅ExpressionVisitor

你可以做:

 public class Renamer : ExpressionVisitor { public Expression Rename(Expression expression) { return Visit(expression); } protected override Expression VisitParameter(ParameterExpression node) { if (node.Name == "a") return Expression.Parameter(node.Type, "something_else"); else return node; } } 

然后, new Renamer().Rename(exp).ToString()应该保持你期望的。

通常我会使用重构工具,例如Jetbrains Resharper来实现。 它有一个“重构,重命名”function,可以让你做到这一点,并知道字符串替换和变量重命名之间的区别。 我知道Visual Studio本身没有这样的function。 http://www.jetbrains.com/resharper/

但是,如果您要引用构建动态表达式,并且想要更改参数,则可以使用以下代码(从c#List 复制到Lambda Expression,带有起始示例:Refactor来处理List )

  // Create a parameter which passes the object ParameterExpression param = Expression.Parameter(typeof(E), "x"); //x replaces a=> // Create body of lambda expression Expression body = Expression.PropertyOrField(param, fieldname); // Create lambda function Expression> exp = Expression.Lambda>(body, param); // Compile it so we can use it Func orderFunc = exp.Compile(); 

要将参数从“x”更改为“y”,我们可以执行以下操作:

  var newExpression = ReplaceFirstParameterName(exp, "y"); private Expression>(Expression> exp, string newParamName) { var cloneParam = Expression.Parameter(exp.Parameters[0].Type, newParamName); var body = exp.Body; var newExp = Expression.Lambda>(body, cloneParam); return newExp; }