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 (key changes bolded):
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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
<span style="font-family: Lucida Console;"><span style="color: #0000ff;">using </span><span style="color: #008080;">System</span><span style="color: #000000;">;</span> <span style="color: #0000ff;">using </span><span style="color: #008080;">System</span><span style="color: #000000;">.</span><span style="color: #008080;">Collections</span><span style="color: #000000;">.</span><span style="color: #008080;">Generic</span><span style="color: #000000;">;</span> <span style="color: #0000ff;">using </span><span style="color: #008080;">System</span><span style="color: #000000;">.Linq;</span> <span style="color: #0000ff;">using </span><span style="color: #008080;">System</span><span style="color: #000000;">.</span><span style="color: #008080;">Text</span><span style="color: #000000;">;</span> <span style="color: #0000ff;">using </span><span style="color: #008080;">System</span><span style="color: #000000;">.</span><span style="color: #008080;">Collections</span><span style="color: #000000;">.</span><span style="color: #008080;">ObjectModel</span><span style="color: #000000;">;</span> <span style="color: #0000ff;">namespace </span><span style="color: #000000;">VisitorPatternConsole</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">public class </span><span style="color: #000000;">Program</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">private static void </span><span style="color: #000000;">Main(</span><span style="color: #0000ff;">string</span><span style="color: #000000;">[] args)</span> <span style="color: #000000;">{</span> <span style="color: #008000;">// NOTE: Using dynamic collections.</span> <span style="color: #808000;">Collection</span><span style="color: #000000;"><<b>dynamic</b>> visitors </span> <span style="color: #000000;">= </span><span style="color: #0000ff;">new </span><span style="color: #808000;">Collection</span><span style="color: #000000;"><<b>dynamic</b>>();</span> <span style="color: #808000;">Collection</span><span style="color: #000000;"><<b>dynamic</b>> pets </span> <span style="color: #000000;">= </span><span style="color: #0000ff;">new </span><span style="color: #808000;">Collection</span><span style="color: #000000;"><<b>dynamic</b>>();</span> <span style="color: #008000;">// Initialize the pets</span> <span style="color: #000000;">pets.Add(</span><span style="color: #0000ff;">new </span><span style="color: #000000;">Fish());</span> <span style="color: #000000;">pets.Add(</span><span style="color: #0000ff;">new </span><span style="color: #000000;">Dog());</span> <span style="color: #008000;">// Initialize the visitors</span> <span style="color: #000000;">visitors.Add(</span><span style="color: #0000ff;">new </span><span style="color: #000000;">Feeder());</span> <span style="color: #000000;">visitors.Add(</span><span style="color: #0000ff;">new </span><span style="color: #000000;">Walker());</span> <span style="color: #008000;">// Visit each of the pets.</span> <span style="color: #0000ff;">foreach </span><span style="color: #000000;">(<b>dynamic </b>pet </span><span style="color: #0000ff;">in </span><span style="color: #000000;">pets)</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">foreach </span><span style="color: #000000;">(<b>dynamic </b>visitor </span><span style="color: #0000ff;">in </span><span style="color: #000000;">visitors)</span> <span style="color: #000000;">{</span> <span style="color: #000000;">visitor.Visit(pet);</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #008000;">// Check the results.</span> <span style="color: #0000ff;">foreach </span><span style="color: #000000;">(Pet pet </span><span style="color: #0000ff;">in </span><span style="color: #000000;">pets)</span> <span style="color: #000000;">{</span> <span style="color: #808000;">Console</span><span style="color: #000000;">.Out.WriteLine(pet.GetType().Name);</span> <span style="color: #0000ff;">foreach </span><span style="color: #000000;">(</span><span style="color: #808000;">String </span><span style="color: #000000;">note </span><span style="color: #0000ff;">in </span><span style="color: #000000;">pet.Visitors)</span> <span style="color: #000000;">{</span> <span style="color: #808000;">Console</span><span style="color: #000000;">.Out.WriteLine(</span><span style="color: #ff00ff;">"\t{0}"</span><span style="color: #000000;">, note);</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Handles the base cases.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public abstract class </span><span style="color: #000000;">AbstractVisitor</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">public void </span><span style="color: #000000;"><b>Visit</b>(<b>Pet pet</b>)</span> <span style="color: #000000;">{</span> <span style="color: #000000;">pet.Visitors.Add(</span> <span style="color: #ff00ff;">"Not supported for this type of pet..."</span><span style="color: #000000;">);</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Concrete visitor, a pet feeder.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public class </span><span style="color: #000000;">Feeder : AbstractVisitor</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">public void </span><span style="color: #000000;">Visit(Dog dog)</span> <span style="color: #000000;">{</span> <span style="color: #008000;">// Feed the dog</span> <span style="color: #000000;">dog.Visitors.Add(</span><span style="color: #ff00ff;">"Fed the dog"</span><span style="color: #000000;">);</span> <span style="color: #000000;">}</span> <span style="color: #0000ff;">public void </span><span style="color: #000000;">Visit(Fish fish)</span> <span style="color: #000000;">{</span> <span style="color: #008000;">// Feed the fish</span> <span style="color: #000000;">fish.Visitors.Add(</span><span style="color: #ff00ff;">"Fed the fish"</span><span style="color: #000000;">);</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Concrete visitor, a pet walker.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public class </span><span style="color: #000000;">Walker : AbstractVisitor</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">public void </span><span style="color: #000000;">Visit(Dog dog)</span> <span style="color: #000000;">{</span> <span style="color: #000000;">dog.Visitors.Add(</span><span style="color: #ff00ff;">"Walked the dog"</span><span style="color: #000000;">);</span> <span style="color: #000000;">}</span> <span style="color: #008000;">// Fish can't be walked!</span> <span style="color: #000000;">}</span> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// Base class for pets.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public abstract class </span><span style="color: #000000;">Pet</span> <span style="color: #000000;">{</span> <span style="color: #0000ff;">private readonly </span><span style="color: #808000;">Collection</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">> visitors;</span> <span style="color: #0000ff;">public </span><span style="color: #808000;">Collection</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">> Visitors</span> <span style="color: #000000;">{</span> <span style="color: #000000;">get { </span><span style="color: #0000ff;">return </span><span style="color: #000000;">visitors; }</span> <span style="color: #000000;">}</span> <span style="color: #0000ff;">protected </span><span style="color: #000000;">Pet()</span> <span style="color: #000000;">{</span> <span style="color: #000000;">visitors = </span><span style="color: #0000ff;">new </span><span style="color: #808000;">Collection</span><span style="color: #000000;"><</span><span style="color: #0000ff;">string</span><span style="color: #000000;">>();</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// A pet fish.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public class </span><span style="color: #000000;">Fish : Pet { }</span> <span style="color: #008000;">/// <summary></span> <span style="color: #008000;">/// A pet dog.</span> <span style="color: #008000;">/// </summary></span> <span style="color: #0000ff;">public class </span><span style="color: #000000;">Dog : Pet { }</span> <span style="color: #000000;">}</span></span> |
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).