2016-08-02 267 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>(); 
     } 
     //... 
    } 
}