Many objects in .NET are stored in a hierarchy. For example: controls, files and folders, and anything you would normally display in a tree view. There are many different algorithms for finding the root of a hierarchy. Here is one of them:
public MyObject GetRoot() { // start with this as root MyObject root = this; // get the parent MyObject parent = this.Parent; // keep going until no more parents while (parent != null) { // save the parent root = parent; // get the parent of the parent parent = parent.Parent; } return root; }
Sample Program
Here is a simple console program that demonstrates this. Note that the function to get the root is a method GetRoot() instead of a Root property. Making it a method instead of a property implies that it must be calculated each time, similar to how the .NET Control class has a FindForm() method.
using System; using System.Collections.Generic; namespace CSharp411 { class Program { static void Main( string[] args ) { MyObject a = new MyObject( "a" ); MyObject b = new MyObject( "b" ); MyObject c = new MyObject( "c" ); MyObject d = new MyObject( "d" ); a.AddChild( b ); b.AddChild( c ); c.AddChild( d ); Write( a ); Write( b ); Write( c ); Write( d ); Console.ReadLine(); } static void Write( MyObject obj ) { string objName = obj.Name; MyObject parent = obj.Parent; string parentName = parent == null ? "none" : parent.Name; MyObject root = obj.GetRoot(); string rootName = root == null ? "none" : root.Name; Console.WriteLine( "Object={0}, Parent={1}, Root={2}", objName, parentName, rootName ); } } class MyObject { public MyObject() { } public MyObject( string name ) { this.m_Name = name; } private string m_Name; public string Name { get { return this.m_Name; } set { this.m_Name = value; } } public override string ToString() { return this.m_Name; } private MyObject m_Parent; public MyObject Parent { get { return this.m_Parent; } } private List<myobject> m_Children = new List</myobject><myobject>(); public void AddChild( MyObject obj ) { this.m_Children.Add( obj ); obj.m_Parent = this; } public IEnumerator</myobject><myobject> Children { get { return this.m_Children.GetEnumerator(); } } public MyObject GetRoot() { // start with this as root MyObject root = this; // get the parent MyObject parent = this.Parent; // keep going until no more parents while (parent != null) { // save the parent root = parent; // get the parent of the parent parent = parent.Parent; } return root; } } }
Program Output
As you would expect, the output when you run this program is:
Object=a, Parent=none, Root=a
Object=b, Parent=a, Root=a
Object=c, Parent=b, Root=a
Object=d, Parent=c, Root=a
How about:
public MyObject GetRoot()
{
if Parent == null
return this;
else
return Parent.GetRoot();
}
Hey Mikey, I like it! (classic cereal commercial reference)
Though the recursive method is 34% slower on my PC (with an average hierarchy depth of 4) it’s nice and clean.