假设我有一个这样的表达式:
Expression<Predicate<T>> exp
如果我指定以下表达式:
a => a.First() != 0
然后我调用exp.ToString()
我将获得我传递的表达式,这非常好,但是,假设我们想要用其他东西更改我们用于'a'的名称,我们该怎么做?
字符串替换不会在所有情况下都有效(它在上面的示例中有效,但是如果参数被称为'i',例如怎么办?)
是否可以只更改参数名称,运行时间,而不影响表达式语义?
更新 @PhilKlein工作得很好,但是需要框架4.但是如果我们需要定位框架3.5,我们可以使用来自ExpressionVisitor的Matt Warren类,只需将protected方法修改为public即可。
答案 0 :(得分:9)
它快速而又脏,但假设您使用的是.NET 4.0,则可以创建以下内容:
public class PredicateRewriter
{
public static Expression<Predicate<T>> Rewrite<T>(Expression<Predicate<T>> exp, string newParamName)
{
var param = Expression.Parameter(exp.Parameters[0].Type, newParamName);
var newExpression = new PredicateRewriterVisitor(param).Visit(exp);
return (Expression<Predicate<T>>) 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
答案 1 :(得分:6)
表达式是不可变的,因此,您无法修改它们, 你需要构建新的树。
在.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()
应该保持您的期望。
答案 2 :(得分:0)
通常我会使用重构工具,例如Jetbrains Resharper来实现。它有一个“重构,重命名”功能,可以让你做到这一点,并知道字符串替换和变量重命名之间的区别。我知道Visual Studio本身没有这样的功能。 http://www.jetbrains.com/resharper/
如果您指的是构建动态表达式,并且想要更改参数,则可以使用以下代码(复制自:c# List<string> to Lambda Expression with starter example: Refactor to handle the 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<Func<E, string>> exp = Expression.Lambda<Func<E, string>>(body, param);
// Compile it so we can use it
Func<E, string> orderFunc = exp.Compile();
要将参数从“x”更改为“y”,我们可以执行以下操作:
var newExpression = ReplaceFirstParameterName(exp, "y");
private Expression<Func<E, string>>(Expression<Func<E,string>> exp, string newParamName)
{
var cloneParam = Expression.Parameter(exp.Parameters[0].Type, newParamName);
var body = exp.Body;
var newExp = Expression.Lambda<Func<string, string>>(body, cloneParam);
return newExp;
}