Visitor Pattern In C# 4.0
I’ve blogged about the Visitor pattern previously and using double dispatch to resolve .NET’s inherent inability to resolve methods by parameter type at runtime.
As I was reading about C# 4.0’s dynamic types, I started to wonder if this would mean that we could finally get a more concise implementation of the pattern. My hunch was correct.
Here is the updated code listing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.ObjectModel; namespace VisitorPatternConsole { public class Program { private static void Main(string[] args) { // NOTE: Using dynamic collections. Collection<dynamic> visitors = new Collection<dynamic>(); Collection<dynamic> pets = new Collection<dynamic>(); // Initialize the pets pets.Add(new Fish()); pets.Add(new Dog()); // Initialize the visitors visitors.Add(new Feeder()); visitors.Add(new Walker()); // Visit each of the pets. foreach (dynamic pet in pets) { foreach (dynamic visitor in visitors) { visitor.Visit(pet); } } // Check the results. foreach (Pet pet in pets) { Console.Out.WriteLine(pet.GetType().Name); foreach (String note in pet.Visitors) { Console.Out.WriteLine("\t{0}", note); } } } } /// <summary> /// Handles the base cases. /// </summary> public abstract class AbstractVisitor { public void Visit(Pet pet) { pet.Visitors.Add( "Not supported for this type of pet..."); } } /// <summary> /// Concrete visitor, a pet feeder. /// </summary> public class Feeder : AbstractVisitor { public void Visit(Dog dog) { // Feed the dog dog.Visitors.Add("Fed the dog"); } public void Visit(Fish fish) { // Feed the fish fish.Visitors.Add("Fed the fish"); } } /// <summary> /// Concrete visitor, a pet walker. /// </summary> public class Walker : AbstractVisitor { public void Visit(Dog dog) { dog.Visitors.Add("Walked the dog"); } // Fish can't be walked! } /// <summary> /// Base class for pets. /// </summary> public abstract class Pet { private readonly Collection<string> visitors; public Collection<string> Visitors { get { return visitors; } } protected Pet() { visitors = new Collection<string>(); } } /// <summary> /// A pet fish. /// </summary> public class Fish : Pet { } /// <summary> /// A pet dog. /// </summary> public class Dog : Pet { } } |
Here is the output:
Wow, just when I thought dynamic was going to suck 😀
What is somewhat interesting is that both collections have to be declared of type dynamic; I’m still mulling this over, but it’s not clear why it doesn’t work if only one of the collections is declared dynamic (I figured that it should have worked if the visitors collection alone was declared dynamic).