C# Programming
07-16-2009, 07:20 PM
Hi,
I'm toying around with generics and have run into a little problem. My class is a tree, but this is not about whether or not one should make a tree this way - what I'm trying to do adds complexity for just a little lazy-coding benefit, so please ignore the particular example - I just want to understand if what I wanted to do can be done with generics.
Here's the TreeNode class:
abstract public class TreeNode
{
TreeNode parent;
List children = new List();
T data;
public TreeNode() { }
public T Data
{
get { return data; }
set { data = value; }
}
public TreeNode Parent
{
get { return parent; }
set { parent = value; }
}
public List Children
{
get { return children; }
set { children = value; }
}
}
Now, let's say we want to derive a class for organizing tags into trees. The data is just a string, and for convenience we may want a constructor that sets the text of the node. I'm trying to see if there is a way to write a utility method that would take any treenode (necessarily derived since the base class is abstract) and a collection of node *data* objects and create child nodes with the data and parent set. The following snippet illustrates the Tag and how code might use the utility method to create a hard-coded hierarchy of tags:
public class Tag : TreeNode
{
public Tag() {}
public Tag(string text) { Data = text; }
}
class usingTags
{
Tag getBuiltIn()
{
Tag root = new Tag("Built-in");
Tag[] top = TreeUtil.Add(root, "License", "Product");
TreeUtil.Add(top[0], "CPOL", "MIT", "Proprietary");
TreeUtil.Add(top[1], "Banco", "Acco", "Piccolo");
return root;
}
}
Based on this, the utility method should be something like this:
static public TNode[] Add(TNode parent, params T[] data) where TNode : TreeNode, new()
{
List list;
if (parent == null)
list = parent.Children;
else
list = new List();
int startIndex = list.Count;
foreach (T item in data) list.Add(new TNode() { Data = item });
return list.GetRange(startIndex, list.Count - startIndex).ToArray();
}
Two problems present themselves:
1) The first assignment to "list" does not build, the compiler complaining it cannot convert List to List, which I think is odd since I have defined a type constraint which guarantees that TNode either is or is derived from TreeNode.
2) If I change that assignment so it assigns null instead, just to be able to build, the code *using* it does not compile. I thought the type of T could be inferred, since TNode is TreeNode and the params T[] parameter is an array of strings. But the compiler just says the method requries two type parameters.
Is there a way to solve these problems so the user of the utility method need only supply the node type to create and the actual values for node data?
I'm toying around with generics and have run into a little problem. My class is a tree, but this is not about whether or not one should make a tree this way - what I'm trying to do adds complexity for just a little lazy-coding benefit, so please ignore the particular example - I just want to understand if what I wanted to do can be done with generics.
Here's the TreeNode class:
abstract public class TreeNode
{
TreeNode parent;
List children = new List();
T data;
public TreeNode() { }
public T Data
{
get { return data; }
set { data = value; }
}
public TreeNode Parent
{
get { return parent; }
set { parent = value; }
}
public List Children
{
get { return children; }
set { children = value; }
}
}
Now, let's say we want to derive a class for organizing tags into trees. The data is just a string, and for convenience we may want a constructor that sets the text of the node. I'm trying to see if there is a way to write a utility method that would take any treenode (necessarily derived since the base class is abstract) and a collection of node *data* objects and create child nodes with the data and parent set. The following snippet illustrates the Tag and how code might use the utility method to create a hard-coded hierarchy of tags:
public class Tag : TreeNode
{
public Tag() {}
public Tag(string text) { Data = text; }
}
class usingTags
{
Tag getBuiltIn()
{
Tag root = new Tag("Built-in");
Tag[] top = TreeUtil.Add(root, "License", "Product");
TreeUtil.Add(top[0], "CPOL", "MIT", "Proprietary");
TreeUtil.Add(top[1], "Banco", "Acco", "Piccolo");
return root;
}
}
Based on this, the utility method should be something like this:
static public TNode[] Add(TNode parent, params T[] data) where TNode : TreeNode, new()
{
List list;
if (parent == null)
list = parent.Children;
else
list = new List();
int startIndex = list.Count;
foreach (T item in data) list.Add(new TNode() { Data = item });
return list.GetRange(startIndex, list.Count - startIndex).ToArray();
}
Two problems present themselves:
1) The first assignment to "list" does not build, the compiler complaining it cannot convert List to List, which I think is odd since I have defined a type constraint which guarantees that TNode either is or is derived from TreeNode.
2) If I change that assignment so it assigns null instead, just to be able to build, the code *using* it does not compile. I thought the type of T could be inferred, since TNode is TreeNode and the params T[] parameter is an array of strings. But the compiler just says the method requries two type parameters.
Is there a way to solve these problems so the user of the utility method need only supply the node type to create and the actual values for node data?