Let's say I need to write an expression visitor, which also uses some injectable service, hence it has to have a public constructor, and cannot be simply wrapped in a static facade.
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;
}
}
Now when I want to use this visitor, I would instantiate it and use it like this
var myExpression = ...;
var myVisitor = new ProcessingVisitor();
myVisitor.Visit(myExpression);
var result = myVisitor.Result;
Now imagine I - for example by accident - run Visit
on another expression. Then Result
will contain both results concatenated. How can I make such a visitor completely "fool proof"? Where could I reset the Result
? I could override Visit
, but I don't know inside if it's called first time, or it's called in the middle of the processing, so I can't reset it there.
Something like this might work (overriding Visit
to track what your root node is):
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;
}
}
Alternatively, you can use an internal class to separate your initializing from your visiting:
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;
}
}