替换BlockExpression的一部分

时间:2015-04-30 12:48:07

标签: c# .net expression expression-trees

这是一个BlockExpression

        var compareTo = GetCompareToExpression<TProperty>(expression, parameters);
        var compareToVariable = compareTo.Key;
        var compareToCall = compareTo.Value;
        var zero = Expression.Constant(0, typeof (int));
        LabelTarget ret = Expression.Label(typeof (int));
        var block = Expression.Block(new[] {compareToVariable},
                                     Expression.Assign(compareToVariable, compareToCall),
                                     Expression.IfThen(Expression.NotEqual(compareToVariable, zero),
                                                       Expression.Return(ret, compareToVariable)),
                                     Expression.Label(ret, zero));
        return block;

及其调试视图:

.Block(System.Int32 $compareItem1) {
    $compareItem1 = .Call ($x.Item1).CompareTo($y.Item1);
    .If ($compareItem1 != 0) {
        .Return #Label1 { $compareItem1 }
    } .Else {
        .Default(System.Void)
    };
    .Label
        0
    .LabelTarget #Label1:
}

现在我需要在另一种方法中用一些自定义逻辑替换.Default(System.Void)。最简单的方法是什么?

2 个答案:

答案 0 :(得分:1)

Expression是不可变的,就像string一样。要修改它们,可以使用所需的更改创建它们的副本。通常,您使用ExpressionVisitor的子类来执行此操作,例如:

public class DefaultVoidExpressionReplacer : ExpressionVisitor
{
    public Expression To;

    protected override Expression VisitDefault(DefaultExpression node)
    {
        if (node.Type == typeof(void))
        {
            return this.Visit(To);
        }
        else
        {
            return base.VisitDefault(node);
        }
    }
}

你就像使用它一样:

var newExpression = new DefaultVoidExpressionReplacer 
    { To = replaceExpression }.Visit(yourExpression);

你甚至可以决定在&#34;更高的&#34;级别:Expression.IfThen级别:

protected override Expression VisitConditional(ConditionalExpression node)
{
    DefaultExpression de = node.IfFalse as DefaultExpression;

    if (de != null && de.Type == typeof(void))
    {
        return base.Visit(Expression.IfThenElse(node.Test, node.IfTrue, To));
    }

    return base.VisitConditional(node);
}

答案 1 :(得分:1)

由于BlockExpression不允许您在适当的位置进行变更(Expressions属性类型为ReadOnlyCollection<Expression>,因此阻止了可能的修改),您需要从旧版本构建一个新块

表达式访问者提供了一种简单的编码方式:

class DefaultReplacer : ExpressionVisitor {
    protected override Expression VisitGoto(GotoExpression g) {
        if (g.Kind != GotoExpressionKind.Return || g.Value == null) {
            return base.VisitGoto(g);
        }
        // If we are here, it's a return expression with Value.
        // Check if Value represents default(System.Void),
        // and return a replacement expression here
        return ...
    }
}

使用此访问者如下:

Expression modifiedBlock = block.Visit(new DefaultReplacer());