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

时间:2011-12-16 22:37:19

标签: c# lambda

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

Expression<Predicate<T>> exp

如果我指定以下表达式:

a => a.First() != 0

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

更新 @PhilKlein工作得很好,但是需要框架4.但是如果我们需要定位框架3.5,我们可以使用来自ExpressionVisitorMatt Warren类,只需将protected方法修改为public即可。

3 个答案:

答案 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;
    }