2016-08-02 269 views
2

我发现了一个问题here差不多回答了我的问题,但我仍然不完全明白。内部类泛型类型与外部类型相同

想写一个树的数据结构,我这样做:

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>>(); 
     } 
     ... 
    } 
} 

而且,谁与C#泛型的工作显然知道,我得到这个编译器警告:Type parameter 'T' has the same name as the type parameter from outer type 'Tree<T>'

我的意图是建立一个内部类将被迫使用与外部类相同的类型,但我现在明白添加一个类型参数实际上允许内部类更灵活。但是,在我的情况,我想的Tree<T>子类可以使用TreeNode,例如,像这样:

public class IntTree : Tree<int> 
{ 
    ... 
    private static IntTree fromNode(TreeNode<int> node) 
    { 
     IntTree t = new IntTree(); 
     t.root = node; 
     return t; 
    } 
} 

(该方法允许子类来实现ToString()递归)

所以我的问题是如果我拿出的参数,如:

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>(); 
     } 
     ... 
    } 
} 

将产生的子类被迫创建TreeNode■当使用一个整数,因此永远无法打破我的意图HA d?

声明:是的,我知道我可能在这里做了很多错误的事情。我仍然在学习C#,它主要来自Java和Lisp背景,并带有一些简单的C语言。因此,欢迎提供建议和解释。

回答

2

是的,它会被强制使用相同的类型。再看看声明:

public class Tree<T> 
{ 
    public class TreeNode 
    { 
     private T Data; 
    } 
} 

所以,当你实例化一个特定Tree确定的Data类型:

var tree = new Tree<int>(); 

这样的Data的类型被声明为int,可以是没有什么不同。

请注意,没有非通用的TreeNode类。仅存在Tree<int>.TreeNode类型:

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]; 

Tree<string>.TreeNode不同型比Tree<int>.TreeNode

+0

好的,这样做更有意义。由于'TreeNode'是一个内部类,所以'TreeNode'不能在没有_typed_'Tree '的情况下创建。所以即使子类可以像'TreeNode'一样使用它,它实际上是隐式地“Tree .TreeNode”。 –

+1

@KristenHammack正是。在'Tree '类中,你可以将它称为'TreeNode',因为编译器知道你的意思。在此范围之外,您必须明确指定您所指的是什么_kind of_'TreeNode'(例如'Tree .TreeNode')。 –

0

在外部类中声明的类型T可能已经在其所有的内部声明中使用,所以你可以简单地从内部类中删除<T>

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>(); 
     } 
     //... 
    } 
}