Изменение имени параметра в LambdaExpression только для отображения - PullRequest
13 голосов
/ 17 декабря 2011

Допустим, у меня есть такое выражение:

Expression<Predicate<T>> exp

Если я назначу следующее выражение:

a => a.First() != 0

и затем я звоню exp.ToString() Я получу именно то выражение, которое я передал, это совершенно хорошо, но, предположим, мы хотим изменить имя, которое мы используем для «а», на что-то еще, как мы можем это сделать? Замена строки не подходит во всех случаях (она работает в приведенном выше примере, но что, если параметр называется «i», например?) Можно ли просто заменить имя параметра во время выполнения, не затрагивая семантическое выражение?

UPDATE @PhilKlein работает отлично, но требует фреймворка 4. Но если нам нужно нацелиться на фреймворк 3.5, мы можем использовать класс ExpressionVisitor из Мэтта Уоррена , просто изменив защищенный для общего доступа Метод посещения.

Ответы [ 3 ]

9 голосов
/ 17 декабря 2011

Это быстро и грязно, но, если вы используете .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
6 голосов
/ 17 декабря 2011

Выражения являются неизменяемыми, поэтому вы не можете их изменять, вам нужно будет создать новое дерево.

В .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() должно содержать то, что вы ожидаете.

0 голосов
/ 17 декабря 2011

Обычно я бы использовал для этого инструмент рефакторинга, например Jetbrains Resharper.Он имеет функцию «Refactor, Rename», которая позволяет вам делать это, и знает разницу между заменой строки и переименованием переменной.Я не знаю такой функции в самой Visual Studio.http://www.jetbrains.com/resharper/

Если вы имеете в виду, однако, создание динамического выражения и хотите изменить параметр, вы можете использовать такой код (скопированный из: c # List в Lambda)Выражение с примером запуска

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...