在LambdaExpression中更改参数名称只是为了显示

本文关键字:显示 LambdaExpression 参数 | 更新日期: 2023-09-27 18:18:01

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

Expression<Predicate<T>> exp

如果我赋值以下表达式:

a => a.First() != 0

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

@PhilKlein工作完美,但需要框架4。但是,如果我们需要瞄准框架3.5,我们可以使用Matt Warren的ExpressionVisitor类,只需将Visit方法从protected修改为public。

在LambdaExpression中更改参数名称只是为了显示

这是快速和肮脏的,但假设您使用的是。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

表达式是不可变的,因此,你不能修改它们。你需要构造一个新的树。

在。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。它有一个"重构,重命名"的特性,可以让你做到这一点,并且知道字符串替换和变量重命名之间的区别。据我所知,Visual Studio本身并没有这样的功能。http://www.jetbrains.com/resharper/

如果你正在构建一个动态表达式,但是,想要改变参数,你可以使用如下代码(复制自:c# List到Lambda表达式与starter示例:重构以处理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;
    }