2009-11-20 60 views
1

可以說我有一個Node類,如下所示編寫一個真正通用的樹:如何使用泛型

class Node<T> 
    { 
     T data; 
     List<Node<T>> children; 
     internal Node(T data) 
     { 
      this.data = data; 
     } 

     List<Node<T>> Children 
     { 
      get 
      { 
       if (children == null) 
        children = new List<Node<T>>(1); 

       return children; 
      } 
     } 

     internal IEnumerable<Node<T>> GetChildren() 
     { 
      return children; 
     } 

     internal bool HasChildren 
     { 
      get 
      { 
       return children != null; 
      } 
     } 

     internal T Data 
     { 
      get 
      { 
       return data; 
      } 
     } 



     internal void AddChild(Node<T> child) 
     { 
      this.Children.Add(child); 
     } 

     internal void AddChild(T child) 
     { 
      this.Children.Add(new Node<T>(child)); 
     } 

    } 

的問題是樹的每一個節點被限制在單一類型。但是,有些情況下,根節點是一種類型,它具有另一種類型的子類型(例如文檔 - >段落 - >行 - >單詞)。

如何爲這種情況定義一個通用樹?

+0

數據對象之間是否有共同點?他們共享相同的接口或基本類型嗎? – Elisha 2009-11-20 11:32:14

+0

不,但它們通常是邏輯連接的,例如上面的文檔 - >參數.....示例。 – logicnp 2009-11-20 13:08:25

+0

如果你不共享一個接口,我認爲你不會得到比節點更好的東西。否則,請與GraemeF一起。我會看看Eric的回答,並重新考慮爲什麼你也使用樹木?也許有更好的結構。 – 2009-11-20 17:20:32

回答

7

如果你想要的類型嚴格的等級,你可以聲明它們是這樣的:

class Node<T, TChild> {...} 

Node<Document, Node<Paragraph, Node<Line, Word>>> 

我並沒有聲稱這將是非常。 :)

+0

這似乎是我能得到的最接近的。但是,我仍然需要在編譯時修復層次結構。對於更深的層次結構來說,它會更加醜陋。 – logicnp 2009-11-20 13:03:28

0

把所有的子對象實現特定的如IDocumentPart然後聲明節點

+0

但是,它不會是一個真正的通用樹。例如,列表不要求你的'T'實現一個特定的接口,你可以選擇你的'T'並創建一個'T'列表 – logicnp 2009-11-20 13:07:24

+0

根據你的評論,也許你想節點。 – 2009-11-20 17:18:19

8

你如何定義這種情況下,一個通用的樹?

我不會嘗試擺在首位。如果我想做的模型:

  • 我有一個文件列表
  • 文檔具有段落的列表
  • 段落有一個單詞列表

那麼你爲什麼根本就需要通用節點?創建一個具有List<Word>的課程,創建一個具有List<Paragraph>的課程文檔,然後創建一個List<Document>,即可完成。爲什麼你需要人爲地強加一個通用的樹結構?這對你有什麼好處?

0

我一直不願意提供附加的代碼示例,感覺我對StackOverFlow的「規範」在發佈可能是「推測性」的代碼方面沒有強烈的理解,感覺這種特殊的嬉戲是某種形式的「突變物種」在實驗室中從「Moreau博士的島上」逃脫:)而且,我認爲Eric Lippert上面的答案是正確的。

所以請在「探測」.NET繼承(使用FrameWork3.5設施)的實驗中,將「一粒鹽」作爲一個實驗。我寫這篇文章(幾個月前)的目標是爲Node實現一個抽象類基礎,它實現了「自身」的一個內部列表<>,然後實現從Abstract類繼承的強類型類......並且在此基礎上,構建一個廣義的樹數據結構。

事實上,當我測試它時,我很驚訝,它的工作!:)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

// experimental code : tested to a limited extent 
// use only for educational purposes 

namespace complexTree 
{ 
    // foundation abstract class template 
    public abstract class idioNode 
    { 
     // a collection of "itself" ! 
     public List<idioNode> Nodes { private set; get; } 

     public idioNode Parent { get; set; } 

     public idioNode() 
     { 
      Nodes = new List<idioNode>(); 
     } 

     public void Add(idioNode theNode) 
     { 
      Nodes.Add(theNode); 
      theNode.Parent = this; 
     } 
    } 

    // strongly typed Node of type String 
    public class idioString : idioNode 
    { 
     public string Value { get; set; } 

     public idioString(string strValue) 
     { 
      Value = strValue; 
     } 
    } 

    // strongly typed Node of type Int 
    public class idioInt : idioNode 
    { 
     public int Value { get; set; } 

     public idioInt(int intValue) 
     { 
      Value = intValue; 
     } 
    } 

    // strongly type Node of a complex type 
    // note : this is just a "made-up" test case 
    // designed to "stress" this experiment 
    // it certainly doesn't model any "real world" 
    // use case 
    public class idioComplex : idioNode 
    { 
     public Dictionary<idioString, idioInt> Value { get; set; } 

     public idioComplex(idioInt theInt, idioString theString) 
     { 
      Value = new Dictionary<idioString, idioInt>(); 
      Value.Add(theString, theInt); 
     } 

     public void Add(idioInt theInt, idioString theString) 
     { 
      Value.Add(theString, theInt); 
      theInt.Parent = this; 
      theString.Parent = this; 
     } 
    } 

    // special case the Tree's root nodes 
    // no particular reason for doing this 
    public class idioTreeRootNodes : List<idioNode> 
    { 
     public new void Add(idioNode theNode) 
     { 
      base.Add(theNode); 
      theNode.Parent = null; 
     } 
    } 

    // the Tree object 
    public class idioTree 
    { 
     public idioTreeRootNodes Nodes { get; set; } 

     public idioTree() 
     { 
      Nodes = new idioTreeRootNodes(); 
     } 
    } 
} 

所以,測試:(調用一些事件處理程序上一個WinForm的代碼):

// make a new idioTree 
    idioTree testIdioTree = new idioTree(); 

    // make a new idioNode of type String 
    idioString testIdioString = new idioString("a string"); 

    // add the Node to the Tree 
    testIdioTree.Nodes.Add(testIdioString); 

    // make a new idioNode of type Int 
    idioInt testIdioInt = new idioInt(99); 

    // add to Tree 
    testIdioTree.Nodes.Add(testIdioInt); 

    // make another idioNode of type String 
    idioString testIdioString2 = new idioString("another string"); 

    // add the new Node to the child Node collection of the Int type Node 
    testIdioInt.Nodes.Add(testIdioString2); 

    // validate inheritance can be verified at run-time 
    if (testIdioInt.Nodes[0] is idioString) MessageBox.Show("it's a string, idiot"); 

    if (!(testIdioInt.Nodes[0] is idioInt)) MessageBox.Show("it's not an int, idiot"); 

    // make a new "complex" idioNode 
    // creating a Key<>Value pair of the required types of idioNodes 
    idioComplex complexIdio = new idioComplex(new idioInt(88), new idioString("weirder")); 

    // add a child Node to the complex idioNode 
    complexIdio.Add(new idioInt(77), new idioString("too weird")); 

    // make another idioNode of type Int 
    idioInt idioInt2 = new idioInt(33); 

    // add the complex idioNode to the child Node collection of the new Int type idioNode 
    idioInt2.Nodes.Add(complexIdio); 

    // add the new Int type Node to the Tree 
    testIdioTree.Nodes.Add(idioInt2); 

    // validate you can verify the type of idioComplex at run-time 
    MessageBox.Show(" tree/2/0 is complex = " + (testIdioTree.Nodes[2].Nodes[0] is idioComplex).ToString()); 

如果這個代碼的「聞」是壞的水果,在這裏在泰國,我們稱之爲「榴蓮」:好,就這樣吧:)在這個實驗中,一個明顯可能的「古怪」是你可以同時在同一棵樹上的多個地方中爲同一個節點引用