Stateful Expression 访问者多个 运行 问题

Stateful Expression visitors multiple run issue

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

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 将包含两个连接的结果。怎样才能让这样的访客完全"fool proof"?我在哪里可以重置 Result?我可以覆盖 Visit,但我不知道它是第一次被调用,还是在处理过程中被调用,所以我不能在那里重置它。

这样的事情可能会起作用(覆盖 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;
    }
}

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

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