The GoF visitor pattern is useful but awkward. The usual c++ or Java-y versions typically involve some kind of visitor interface which your visitor must subclass. Java somewhat mitigates this with anonymous classes, but not fully. In C#, if we’re clever with the use of delegates, we can make tasks like tree traversal look about as simple as iteration.
Let’s start with a simple tree class:
class Node {
Node[] children;
}
We’ll implement a depth-first search using the visitor pattern. Using delegates, we can eliminate the need for an additional class:
class Node {
public Node[] children;
public delegate void VisitorDelegate(Node currentNode);
public void Traverse(VisitorDelegate visitor)
{
foreach(Node n in children)
{
Traverse(n);
}
visitor(this);
}
}
This is a pretty simple recursion, and really isn’t anything special. The way delegates are typically used, there is still an additional method required for the delegate to be called. But with C# 2.0, we have the opportunity to use anonymous delegates. This is where we can write some really slick code:
void TestTraversal()
{
Node root = GenerateTestTree();
int nodeCount = 0;
root.Traverse(delegate(Node n)
{
nodeCount++;
});
}
The really cool thing about this is that, since anonymous delegates can act as closures, our visitor can pull in the nodeCount from the surrounding environment. This makes for a very succinct version of the visitor pattern.
Technorati Tags: c#, programming
9 responses so far ↓
mcgurk // October 4, 2007 at 12:42 pm
You’ve got a bug in your code.
foreach(node n in children)
{
traverse(n);
}
mullr // October 4, 2007 at 5:33 pm
Ah, so it is, thanks. Should’ve written unit tests for the post.
Tim // October 4, 2007 at 8:18 pm
1. Simple + powerful = nice trick!
2. What tool are you using to generate that seductively-formatted code?
mullr // October 4, 2007 at 8:28 pm
It’s actually a wordpress feature: you simply enclose the code in question with
Tim // October 4, 2007 at 9:17 pm
Whoa, thanks!
seregaborzov // October 6, 2007 at 8:01 pm
Good Job, great post, useful blog. Thanks!
Hello from Russia =)
One question: I can translate your some posts to my Russian readers?
mullr // October 8, 2007 at 4:01 pm
seregaborzov: Yes, of course you can. I’m flattered!
B3ardman // October 9, 2007 at 10:20 am
It’s worth noting that List().ForEach implements this pattern too.
And so do some of the other helpers on List.
I just wish they were static and accepted anything implementing IEnumerable
seregaborzov // October 29, 2007 at 6:17 pm
ok, i’am write about design patterns http://seregaborzov.wordpress.com/category/design-patterns/
and your’s posts can help me!
Thanks =)
Leave a Comment