有状态表达式访问者多次运行问题

时间:2016-01-14 15:08:39

标签: c# expression linq-expressions visitor

让我们说我需要编写一个表达式访问者,它也使用一些可注入服务,因此它必须有一个公共构造函数,并且不能简单地包装在静态外观中。

public class ProcessingVisitor : ExpressionVisitor {

  IProcessor _processor;
  public string Result { get; private set; }

  public ProcessingVisitor(IProcessor processor) {
    _processor = processor;
  }

  protected override Expression VisitBinary(BinaryExpression node)
  {
    // visit left and right
    // ... and do something with _processor
    Result += // ... append something to result
    return node;
  }
}

现在,当我想使用这个访问者时,我会实例化它并像这样使用它

var myExpression = ...;
var myVisitor = new ProcessingVisitor();
myVisitor.Visit(myExpression);
var result = myVisitor.Result;

现在想象一下 - 例如偶然 - 在另一个表达式上运行Visit。然后Result将包含两个连接的结果。我怎样才能完全成为这样一个访客"傻瓜证明"?我在哪里可以重置Result?我可以覆盖Visit,但我不知道内部是否第一次调用,或者在处理过程中调用它,所以我无法重置它在那里。

1 个答案:

答案 0 :(得分:1)

这样的事情可能会起作用(覆盖Visit来跟踪你的根节点是什么):

public class ProcessingVisitor : ExpressionVisitor
{

    IProcessor _processor;
    private Expression _rootExpression = null;
    public string Result { get; private set; }

    public ProcessingVisitor(IProcessor processor)
    {
        _processor = processor;
    }

    protected override Expression VisitBinary(BinaryExpression node)
    {
        // visit left and right
        // ... and do something with _processor
        Result += "";// ... append something to result
        return node;
    }
    public override Expression Visit(Expression node)
    {
        if (_rootExpression == null)
        {
            _rootExpression = node;
            Result = null;
        }

        var toReturn = base.Visit(node);

        if (_rootExpression == node)
            _rootExpression = null;
        return toReturn;
    }
}

或者,您可以使用内部课程将初始化与访问分开:

public class ProcessingVisitor : ExpressionVisitor
{

    IProcessor _processor;

    #region Inner Class
    internal class _Implementation : ExpressionVisitor
    {
        IProcessor _processor;
        internal string Result { get; set; }

        internal _Implementation(IProcessor processor)
        {
            _processor = processor;
        }

        protected override Expression VisitBinary(BinaryExpression node)
        {
            // visit left and right
            // ... and do something with _processor
            Result += "";// ... append something to result
            return node;
        }

        internal Expression VisitFresh(Expression node)
        {
            Result = null;
            return base.Visit(node);
        }
    }
    #endregion

    public string Result { get; private set; }
    public ProcessingVisitor(IProcessor processor)
    {
        _processor = processor;
    }

    public override Expression Visit(Expression node)
    {
        var impl = new _Implementation(_processor);
        var toReturn = impl.VisitFresh(node);
        Result = impl.Result;
        return toReturn;
    }
}