Reputation: 399
I found a question here that almost answers my question, but I still don't fully understand.
Trying to write a Tree data structure, I did this:
public class Tree<T>
{
public TreeNode<T> root;
...
public class TreeNode<T>
{
List<TreeNode<T>> children;
T data;
public T Data { get { return data; } }
public TreeNode<T>(T data)
{
this.data = data;
children = new List<TreeNode<T>>();
}
...
}
}
And, anyone who's worked with C# generics apparently knows that I got this compiler warning: Type parameter 'T' has the same name as the type parameter from outer type 'Tree<T>'
My intent was to create an inner class that would be forced to use the same type as the outer class, but I now understand that adding a type parameter actually allows the inner class to be more flexible. But, in my case, I want subclasses of Tree<T>
to be able to use TreeNode
, for example, like this:
public class IntTree : Tree<int>
{
...
private static IntTree fromNode(TreeNode<int> node)
{
IntTree t = new IntTree();
t.root = node;
return t;
}
}
(That method allows the subclass to implement ToString()
recursively)
So my question is, if I take out the parameterization, like this:
public class Tree<T>
{
public TreeNode root;
...
public class TreeNode
{
List<TreeNode> children;
T data;
public T Data { get { return data; } }
public TreeNode(T data)
{
this.data = data;
children = new List<TreeNode>();
}
...
}
}
will the resulting subclass be forced to use integers when creating TreeNode
s, and therefore never be able to break the intent I had?
Disclaimer: yes, I know I'm probably doing plenty of things wrong here. I'm still learning C#, coming from a mostly Java and Lisp background, with a little bit of plain C. So suggestions and explanations are welcome.
Upvotes: 4
Views: 2295
Reputation: 43886
Yes, it will be forced to use the same type. Look at the declaration again:
public class Tree<T>
{
public class TreeNode
{
private T Data;
}
}
So the type of Data
is determined when you instantiate a specific Tree
:
var tree = new Tree<int>();
This way the type of Data
is declared as int
and can be no different.
Note that there is no non-generic TreeNode
class. There is only a Tree<int>.TreeNode
type:
Tree<int> intTree = new Tree<int>(); // add some nodes
Tree<int>.TreeNode intNode = intTree.Nodes[0]; // for example
Tree<string> stringTree = new Tree<int>(); // add some nodes
Tree<string>.TreeNode stringNode = stringTree.Nodes[0]; // for example
// ERROR: this won't compile as the types are incompatible
Tree<string>.TreeNode stringNode2 = intTree.Nodes[0];
A Tree<string>.TreeNode
is a different type than Tree<int>.TreeNode
.
Upvotes: 3
Reputation: 9650
The type T
declared in the outer class may already be used in all its inner declarations, so you can simply remove the <T>
from the inner class:
public class Tree<T>
{
public TreeNode root;
//...
public class TreeNode
{
List<TreeNode> children;
T data;
public T Data { get { return data; } }
public TreeNode(T data)
{
this.data = data;
children = new List<TreeNode>();
}
//...
}
}
Upvotes: 1