我知道如何用ExpressionVisitor替换参数,但我想知道是否有从Expression.Block中删除参数的方法。
理想情况下,我应该抓取整个表达式树,并在每次在块中声明它时删除参数。
知道如何使用ExpressionVisitor吗?
答案 0 :(得分:1)
一个简单的类,用于从BlockExpression
中删除局部变量,并将其替换为您想要的任何内容。
public class BlockVariableRemover : ExpressionVisitor
{
private readonly Dictionary<Expression, Expression> replaces = new Dictionary<Expression, Expression>();
public readonly Func<ParameterExpression, int, Expression> Replacer;
public BlockVariableRemover(Func<ParameterExpression, int, Expression> replacer)
{
Replacer = replacer;
}
protected override Expression VisitBlock(BlockExpression node)
{
var removed = new List<Expression>();
var variables = node.Variables.ToList();
for (int i = 0; i < variables.Count; i++)
{
var variable = variables[i];
var to = Replacer(variable, i);
if (to != variable)
{
removed.Add(variable);
replaces.Add(variable, to);
variables.RemoveAt(i);
i--;
}
}
if (removed.Count == 0)
{
return base.VisitBlock(node);
}
var expressions = node.Expressions.ToArray();
for (int i = 0; i < expressions.Length; i++)
{
expressions[i] = Visit(expressions[i]);
}
foreach (var rem in removed)
{
replaces.Remove(rem);
}
return Expression.Block(variables, expressions);
}
public override Expression Visit(Expression node)
{
Expression to;
if (node != null && replaces.TryGetValue(node, out to))
{
return base.Visit(to);
}
return base.Visit(node);
}
}
使用它像:
Expression<Func<int, int>> exp;
{
var var1 = Expression.Variable(typeof(int), "var1");
var var2 = Expression.Variable(typeof(long), "var2");
var par1 = Expression.Parameter(typeof(int), "par1");
var block = Expression.Block(new[] { var1, var2 }, Expression.Increment(var1));
exp = Expression.Lambda<Func<int, int>>(block, par1);
// Test
var compiled = exp.Compile();
Console.WriteLine(compiled(10));
}
// Begin replace
{
var par1 = exp.Parameters[0];
var block2 = new BlockVariableRemover(
// ix is the index of the variable,
// return x if you don't want to modify,
// return whatever you want (even Expression.Empty()) to do
// a replace
(x, ix) => ix == 0 && x.Type == typeof(int) ? par1 : x)
.Visit(exp.Body);
// Final result
var exp2 = Expression.Lambda<Func<int, int>>(block2, par1);
// Test
var compiled = exp2.Compile();
Console.WriteLine(compiled(10));
}