A nice use for Nested classes in C#
In C# you can put classes in a namespace like this:
namespace Foo { public class Bar {...} }
or nest them like this:
public class Foo { public class Bar(){...} }
Nesting classes in C# is more like C++ than Java (creating a new Foo does not imply a new Bar), so deciding which to use is to some extent a stylistic decision. That said I ran into an interesting place where nesting turned out to have a subtle advantage. I had a common base class with a bunch of derived classes, each representing a particular type of input (statements in a program in this case), so something like this:
abstract class Statement { public class FooStatement : Statement {...} public class BarStatement : Statement {...}
static public CreateStatement() { /* returns a foo or bar statement */ } }
Wow, what has Jason been smoking? Nesting subclasses like this is just evidence of his dementia, no? At the time I wrote this code I was betting that the outside world wouldn't care what particular thing came back from CreateStatement, so I just hid the possible ones inside Statement. It's not like anyone was ever going to derive new Statement classes, and if they did they'd have the source here, so they could just nest it in with the rest of them.
Of course there were parts of the outside world that did wind up caring what type of Statement they had. For that code this decision turned out annoying. I couldn't use the using keyword as a shortcut so I had to declare variables of type Statement.FooStatement which was a bit awkward.
The advantage of doing things this way emerged later. The key turns out to be that given a Type object you can enumerate over its NestedTypes collection to see the contained subtypes. You can't do this with namespaces, because namespaces can be arbitrarily extended into new assemblies. This was a super nice thing to be able to do. For example, I wanted to keep a Hashtable to track how many occurences of each type of statements appeared in a program so that I could do some simple optimizations. A few lines of reflection code salted the table very nicely:
Hashtable OccurencesOf = new Hashtable();
Type t = typeof(Statement); foreach(Type c in t.GetNestedTypes()) { OccurencesOf[c] = 0; }
This was so nice - I could just add new nested types inside of Statement and they got automatically picked up and added to the table. Other code could just say things like this.
Statement s = Statement.CreateStatement(); OccurencesOf[s.GetType()]++;
All of it just...worked.. without me having to keep track of filling the tables with macros or something. As a reformed ATL nut I really appreciate this. Reflection-driven code can be so amazing. Not exactly rocket science but these little gems are what make it all fun...
12:23:44 AM
|