本文介绍了在Expression.Block中查找并删除参数声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如何用ExpressionVisitor替换参数,但是我想知道是否有一种方法可以从Expression.Block中删除参数.

I know how to replace a parameter with ExpressionVisitor but I was wondering if there's a way to remove a parameter from a Expression.Block.

理想情况下,每次在块内声明参数时,我都应爬网整个表达式树并删除该参数.

Ideally I should crawl the entire Expression tree and remove the parameter every time it is declared inside a Block.

有人知道如何使用ExpressionVisitor做到这一点吗?

Any idea how to do that with ExpressionVisitor?

推荐答案

一个简单的类,用于从BlockExpression中删除局部变量并将其替换为所需的任何内容.

A simple class to remove local variables from a BlockExpression and replace them with whatever you want.

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));
}

这篇关于在Expression.Block中查找并删除参数声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-27 05:03