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