如何使用泛型编写真正通用的树

时间:2009-11-20 11:28:14

标签: c# .net generics

假设我有一个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));
        }

    }

问题是树的每个节点都被限制在一个类型中。但是,存在根节点是一种类型的情况,其具有另一种类型的子节点,其具有第三类型的子节点(示例文档 - &gt;段落 - &gt;行 - >单词)。

如何为这种情况定义通用树?

4 个答案:

答案 0 :(得分:8)

  

如何为这种情况定义通用树?

我不会首先尝试。如果我想模拟的是:

  • 我有一份文件清单
  • 文档包含段落列表
  • 段落有一个单词列表

那为什么你需要通用节点呢?创建一个具有List<Word>的类段落,创建一个具有List<Paragraph>的类文档,然后创建一个List<Document>并完成。为什么需要人为地施加通用树结构?这会给你带来什么好处?

答案 1 :(得分:8)

如果你想要一个严格的类型层次结构,你可以像这样声明它们:

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

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

我没有声称它会很漂亮。 :)

答案 2 :(得分:0)

我一直不愿意提供所附的代码示例,感觉我对StackOverFlow的“规范”在发布可能是“推测性”的代码方面没有强烈意义,并且感觉到这个特殊的嬉戏是某种形式的“突变物种”从实验室逃出“莫罗博士岛”:)而且,我认为上面的Eric Lippert的回答是正确的。

因此,请将“一粒盐”作为“探测”.NET继承(使用FrameWork 3.5工具)的实验。我写这篇文章(几个月前)的目的是尝试实现内部List&lt;&gt;的Node结构的抽象类基础。然后,实现“自身”,然后实现从Abstract类继承的强类型类...并在此基础上构建一个通用的Tree数据结构。

事实上,当我测试它时,我感到很惊讶,它有效! :)

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上的一些EventHandler调用此代码):

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

如果这段代码的“气味”与泰国的水果一样糟糕,我们称之为“榴莲”:好吧,就这样吧:)这个实验中一个明显可能的“怪异”是你可以有参考同时在树中的多个位置中的

答案 3 :(得分:0)

让所有子对象实现特定的IDocumentPart,然后声明Node