Visitor Pattern Revisited with C# 4

The Visitor Pattern is a well known pattern that has good uses but so far been rather awkward or ugly to implement in C# versions prior to 4.

The visitor pattern is useful in scenarios in which you need to implement different behaviors for different objects within a class hierarchy, but you do not want to use virtual or abstract methods to achieve this. A good example is serialization logic for a hierarchy of objects. In general, if you want to adhere to the Single Responsibility Principle, you do not want your objects that hold domain data also to deal with algorithms for implementation of certain tasks.

Let us imagine that we have a class hierarchy as follows:

public abstract class Product {..}
public class Book : Product {..}
public class Record : Product {..}
public class Movie : Product {..}

Let us also say that we want to implement some kind of serialization for these classes. One way to do this is to add an abstract Serialize() method to Product class and then have each class override it. However this approach will break the Single Responsibility and Encapulsation principles for your objects, and even then, it might not be feasible as the objects might even be residing in a seperate assembly that is out of your control. The preferred way in this scenario to extend the behavior of your classes is to use a Visitor class that will implement the specific behavior for each class in the hierarchy.

An example:

public class ProductSerializer
{        
    public void Serialize(Book b) { }
    public void Serialize(Record r) { }
    public void Serialize(Movie m) { }
}

There is one thing missing here. There is no implementation for Serialize(Product p). As the C# is a statically typed language, when you have the following code, it will not compile:

Product product = new Book();
var serializer = new ProductSerializer();
serializer.Serialize(product);

Even though it is obvious that the product is of type Book, and there is an implementation of the Serialize method with Book as a parameter, due to static typing the compiler will bind the method during compilation and thus requires you to have a method with the signature Serialize(Product p). How would we go around implementing such a method in pre-C# 4 world? Here is where it gets ugly and awkward:

public void Serialize(Product p)
{
    if (p is Book) Serialize(p as Book);
    if (p is Record) Serialize(p as Record);
    if (p is Movie) Serialize(p as Movie);
}

This also means that you need to add methods for every new class in hierarchy as well. Image if the visitor pattern involved two arguments and then you would need to take into account all combinations of parameters. So is there a better way to do this?

C# 4.0 introduced dynamic keyword and dynamic dispatch, which we can utilize for a good cause in a scenario like this.

The above awkward and verbose implementation of Serialize can now be replaced with a much cleaner one as follows:

public void Serialize(Product p)
{
  Serialize((dynamic)p);
}

So how does this magic work? The dynamic keyword in itself is a type. The difference is that it tells the compiler to resolve the type during the runtime instead of on compile time. The compiler will bind the statically typed Serialize call above to always the same method, which is Serialize(Product p), no matter the actual type of the instance because the reference is of type Product. However, when p is cast as dynamic, the compiler defers the decision of choosing the proper method overload to runtime and will not care about what the reference is during compile time. It will see that the passed in parameter is a Book and as such will choose the most appropriate method during runtime. There is a certain performance hit, of course, but it is with most respects minimal and the benefit of having clean code is much higher.

Advertisements