BaseUnit > Unit > ContainerUnit
- BaseUnit is the core class.
- Unit adds a ContainerUnit property called Parent.
- ContainerUnit adds a List<Unit> property called Children.
So, all Unit types (including ContainerUnit) must have a parent that is a ContainerUnit. ContainerUnit types can have children that are ContainerUnit types or just Unit types.
So you can have a box of items, some of which are boxes of items.
I want to have a master ContainerUnit that is treated as the highest level parent of all Unit types. But that would make its Parent property null. Meaning, I want to say “who’s your daddy?” to anything, without being aware of its position in the hierarchy, but then if I ask (say, in a loop) who the master container’s parent is, it gets handled gracefully.
I’m looking for approaches that others have taken to solve this. I did search for this, I just didn’t have much luck with my queries.
Having the outermost “universe” container return null for its container is the traditional thing to do. This has the advantage that it is easy. It has the disadvantage that you don’t know that you’ve gone past the edge of the universe until it is too late to get back. As you said in a comment: using “null” as a flag is weak.
Two other solutions that I’ve seen employed are:
1) The universe object is its own container. This has the advantage that nothing is null; it has the disadvantage that it is easy to go into an infinite loop when walking the container chain, and it is unintuitive; the universe does not actually contain itself. Basically you’re using equality as a flag instead of nullability as a flag; this seems weak too.
2) The universe object throws an exception when you ask for the container. This forces the caller to, instead of checking for null container, check instead for “are you the entire universe?” before asking for the container. That is, stop when you get to the top, instead of stopping when you get beyond the top. This is actually a kind of nice solution because it forces people to write defensive code. You can’t just ask for a container unless you know there is one. Of course, it requires that the caller be somehow able to identify the universe object without inspecting its parent. You need an “Am I the entire universe?” method, or a well-known singleton object to compare against, or some other mechanism for identifying which is the topmost container.
A third approach is to deny the premise of the question; is it possible to construct your data type so that the container need not be known, or such that the importance of knowing it is minimized?
For example, in the compiler of course we have lots of “container” chains to walk, and we signal the global namespace by having its containing symbol be null (and by it being a well-known singleton object.) But a lot of the time we don’t need to ever check for whether the parent is null because instead I write code that builds an abstraction on top of it:
Great. Now that I have that helper method, I don’t ever need to check the Container property of a thing. If I want to know, “is there any container of this thing that contains this other thing?” then I can say:
Use the power of LINQ to move mechanistic implementation details like “how do I determine when I’m at the top?” into higher-level helper methods. Then write your logic in at the “business” level, not at the “mechanism” level.