Reflective Visitor using C#

There is a well known design pattern in the Object Oriented world: The Visitor pattern.

This pattern, among other things, allows to extend an object without actually modifying it. It is fairly easy to implement in any good OO language such as C++, Java or C#.

However, there is a problem with the implementation of this pattern, or rather an implementation limitation. It requires the base interface or abstract class for all visitors to define at most one method for each type that may visit it. This is not a problem by itself, but it requires to modify the visitor base each time you add a new type. The best way to do this would be to call the appropriate method based on the caller type.

.NET provides that kind of behavior through reflection, as it is possible to find a method based on its parameters at runtime.

I decided to try this out with the C# 2.0 and its generics :)

Here what I came up with :

public interface IOperand
{
 
IOperand Accept(Visitor visitor, IOperand
right);
}

public class Operand< T> : IOperand
{
  private
T _value;

  public
Operand(T value)
 
{
   
_value = value;
 
}
  public IOperand Accept(Visitor v, IOperand
right)
 
{
    return v.Visit(this
, right);
  }
  public T Value
  {
    get { return
_value; }
 
}
  public override string ToString()
  {
    return string.Format("{0} ({1})", _value, GetType());
  }
}

This is the definition of an operand, which is used in a abstract machine to perform operations on abstract types. This class is generic, I did not want to implement all the possible types.

Then here is the visitor :

public class Visitor
{
 
public virtual IOperand Visit(IOperand left, IOperand right)
 
{
   
MethodInfo info = GetType().GetMethod("Visit", new Type[] { left.GetType(), right.GetType() });
   
   
if (info != null && info.DeclaringType != typeof(Visitor))
     
return info.Invoke(this, new object[] { left, right }) as IOperand;

    
Console.WriteLine("Operation not supported");
   
return null;
  
}
}

This method search in the current type all methods named "Visit" that take the actual type of the parameters left and right and tries to match a method with it. Also, to avoid looping through the same method we're in since it's matching everything, there is a test for the type declaring the method.

Now the AdditionVisitor :

public class AdditionVisitor : Visitor
{
  public IOperand Visit(Operand<int> value, Operand<int> right)
  {
    return new Operand<int>(value.Value + right.Value);
  }
  public IOperand Visit(Operand<int> value, Operand<short> right)
  {
    return new Operand<int>(value.Value + right.Value);
  }
  public IOperand Visit(Operand<double> value, Operand<int> right)
  {
    return new Operand<double>(value.Value + right.Value);
  }
}

Which defines a bunch of visitable methods used to add different operations on IOperand-like types.

And finally to use it :

class Program
{
  static void Main(string[] args)
  {
    Operand<int> a = new Operand<int>(21);
    Operand<short> b = new Operand<short>(21);
    Console.WriteLine(Add(a, b));
  }

 
static IOperand Add(IOperand a, IOperand b)
 
{
   
AdditionVisitor addVisitor = new AdditionVisitor();
   
return a.Accept(addVisitor, b);
 
}
}

Using this Reflective Visitor, modifying the base visitor class is not needed anymore, which limits the modifications to one class only. Of course, there's room for optimization, for instance by avoiding the method lookup using the System.Reflection namespace, but you get the picture.

Some asked me what could be done in .NET that could not be done in C++, this is an example of it :)

Publié samedi 2 avril 2005 21:15 par jay
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires


Les 10 derniers blogs postés

- TechDays Paris 2012 : Session pleinière jour 3 par Blog Technique de Romelard Fabrice le 02-09-2012, 11:01

- Mishra Reader : un lecteur RSS très Zune Style en Open Source ! par Cyril Sansus le 02-09-2012, 08:28

- [framework 4] Les Tasks et le Thread UI par Fathi Bellahcene le 02-09-2012, 00:33

- Workflow Foundation 3 a un pied dans la tombe par Blog de Jérémy Jeanson le 02-08-2012, 22:15

- TechDays Paris 2012 : Nouvelles tendances du poste de travail - Bring Your own PC par Blog Technique de Romelard Fabrice le 02-08-2012, 19:42

- TechDays Paris 2012 : System Center Service Manager 2012 Vue d’ensemble par Blog Technique de Romelard Fabrice le 02-08-2012, 17:32

- TechDays Paris 2012 : Pleinière second jour par Blog Technique de Romelard Fabrice le 02-08-2012, 16:23

- TechDays Paris 2012 : Retour d'expérience sur la mise en place d'un Cloud Privé par Blog Technique de Romelard Fabrice le 02-08-2012, 16:04

- TechDays Paris 2012 : Comment SharePoint a sauvé mes TechDays par Blog Technique de Romelard Fabrice le 02-07-2012, 23:59

- Perspective 3.0 pour Silverlight 5.0 par Perspective le 02-07-2012, 22:39