The problem with your approach is that Data
can be any type. Your design allows you to put multiple types into the same tree. So one node might have a string
and the other might have a double
, and a third could have a reference to a user-defined type. If you make the Node
constructor take an IComparable
instance, you're assuming that all of the items in the tree will be of the same type, or that their IComparable
interface implementations know how to compare values of all possible data types.
In short, whereas what you did will work, it's not at all type safe.
What you have is a very C-like thing to do. In C++, you'd use templates to avoid this kind of abomination. In C#, you use generics.
I echo the suggestion made in the comments: if you want a generic data structure, make a generic data structure. Using the built-in collections, for example, if you want a list of integers you write:
var list_of_integers = new List<int>();
And if you want a list of strings:
var list_of_strings = new List<string>();
If you want to create a generic tree collection, you'd start with:
public class MyGenericTree<T>
{
public class Node
{
public T Data;
public Node Left;
public Node Right;
public Node(T data)
{
Data = data;
}
}
private readonly IComparer<T> _comparer;
public MyGenericTree(IComparer<T> comparer = null)
{
_comparer = comparer ?? Comparer<T>.Default;
}
}
And you create it with:
var myTree = new MyGenericTree<string>(); // or int, or whatever type
If you want a custom comparison function, you write:
// Create a tree that stores case-insensitive strings
var myTree = new MyGenericTree<string>(StringComparer.CurrentCultureIgnoreCase);
This forces the Data
to always be of a compatible type. And you either use the default comparer for that type, or the comparer interface that you pass to the constructor.
And when doing the comparisons, it's:
int a = _comparer.Compare(node1, node2);
if (a < 0)
// node1 < node2
else if (a > 0)
// node1 > node2
else
// node1 == node2
If you really do want to store untyped object
references in the tree, you can easily write:
var myTree = new MyGenericTree<object>(some_object_comparer);
Although why you'd want to do such a thing is a bit of a mystery.
I know that the generics look a little weird to start, but after a day or so of working with them, you grasp the idea that they're quite flexible as well as being type safe.