【发布时间】:2017-05-24 12:08:25
【问题描述】:
我正在使用以下方法将 ParameterExpression 替换为另一个:
public static Expression ReplaceParameter( this Expression expression,
ParameterExpression parameter, string name )
{
return new ExpressionParameterReplacer( parameter, name ).Visit( expression );
}
internal class ExpressionParameterReplacer : ExpressionVisitor
{
private readonly ParameterExpression _parameter;
private readonly string _name;
protected override Expression VisitParameter( ParameterExpression node )
{
if( node.Name == _name && (node.Type == _parameter.Type ||
node.Type.IsAssignableFrom( _parameter.Type )) )
{
return base.VisitParameter( _parameter );
}
return base.VisitParameter( node );
}
internal ExpressionParameterReplacer( ParameterExpression parameter, string name )
{
_parameter = parameter;
_name = name;
}
}
我是这样使用的:
ParameterExpression value = Expression.Parameter( ..., "value" );
return Expression.Block
(
new[] { value },
Expression.Assign( value, valueGetter ),
SomeLambdaExpression.Body.ReplaceParameter( value,
SomeLambdaExpression.Body.Parameters[0].Name);
)
正如你所见,为了替换参数,我需要声明并分配一个新的临时参数表达式。
我想知道是否有办法避免这项工作并将 ParameterExpression 直接替换为提供值的表达式 (valueGetter)。
这样的事情要清楚:
return SomeLambdaExpression.Body.ReplaceParameter( valueGetter,
SomeLambdaExpression.Body.Parameters[0].Name);
【问题讨论】:
-
你应该按实例替换参数,而不是按名称和类型,这可能会导致错误!删除名称,并使用提供的表达式中的参数。示例:stackoverflow.com/questions/29448432/…MultiParamReplaceVisitor
-
@MBoros 完全错误!如果你有两个相同类型的参数,你会怎么做?您肯定需要名称来确定要替换哪个!
-
这就是为什么你用 INSTANCE 代替(不是类型)。这个名字没有任何意义。在 list => list.Where(x => x > 4).Select(x => x + 1) 中,您有 2 个不同的参数,均为 int 类型,名称为 x。这是一棵表达式树。您可以手动构建所有参数都称为相同的树,内部参数可以与外部参数具有相同的名称和类型。你必须通过 INSTANCE 去。
-
啊,好吧,我明白你的意思了。在我的例子中,参数实例在构建复杂表达式的过程中丢失了。我没有对任何 ParameterExpression 实例的引用,因此为了替换它们,我知道您不能在同一范围内声明具有相同名称的变量,因此我对每个范围执行替换。看看我在 github 上的项目:UltraMapper。
-
嗯,根据我的经验,这是一种非常糟糕的做法,可能会导致严重的头痛。如果您有 lambda 表达式的主体,则内部范围可能会定义具有相同名称/类型的参数。然后在内部范围内,您仍然需要实例比较。例如 Exp
> pred = x => x > 3; var ints = new List (); Exp > pred2 = x => ints.AsQueryable(pred);想象一下有人设法在 pred2 中实际引用了 pred(不仅仅是对闭包的字段访问),这并不难。如果你手头只有 pred2.Body,你怎么知道 x>3 中的哪个 x?
标签: c# expression-trees expressionvisitor