In this entry I'm revisting the Visitor Pattern, this time using C# 2.0 generics rather than Java generics.
One addition to the previous design is to declare two interaces, one for a void return and one for a non-void return:
public interface IVisitable
{
void Accept(IVisitor visitor);
R Accept(IVisitor1<R> visitor);
}
public interface IVisitor
{
void Visit(A visited);
void Visit(B visited);
void Visit(C visited);
}
public interface IVisitor1<R>
{
R Visit<R>(A visited);
R Visit<R>(B visited);
R Visit<R>(C visited);
}
Each concrete element then simply implements both Accept methods:
public class A : IVisitable
{
...
public void Accept(Visitor visitor)
{
visitor.Visit(this);
}
public R Accept<R>(Visitor1<R> visitor)
{
return visitor.Visit(this);
}
...
}
I could do this in Java too of course. However, the C# version edges out the Java version in two respects. First, C# allows two types to have the same name as long as they have a different number of generic arguments.
public interface IVisitor
{
void Visit(A visited);
void Visit(B visited);
void Visit(C visited);
}
public interface IVisitor<R>
{
R Visit<R>(A visited);
R Visit<R>(B visited);
R Visit<R>(C visited);
}
Secondly, generic IVisitor works with all types (including value types such as bool) without the need for wrapper classes:
public class ExampleVisitor : IVisitor<bool>
{
public bool Visit(A visited) { ... }
public bool Visit(B visited) { ... }
public bool Visit(C visited) { ... }
}