假设我有一个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;行 - >单词)。
如何为这种情况定义通用树?
答案 0 :(得分:8)
如果你想要一个严格的类型层次结构,你可以像这样声明它们:
class Node<T, TChild> {...}
Node<Document, Node<Paragraph, Node<Line, Word>>>
我没有声称它会很漂亮。 :)
答案 1 :(得分:8)
如何为这种情况定义通用树?
我不会首先尝试。如果我想模拟的是:
那为什么你需要通用节点呢?创建一个具有List<Word>
的类段落,创建一个具有List<Paragraph>
的类文档,然后创建一个List<Document>
并完成。为什么需要人为地施加通用树结构?这会给你带来什么好处?
答案 2 :(得分:0)
让所有子对象实现特定的IDocumentPart,然后声明Node
答案 3 :(得分: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());
如果这段代码的“气味”与泰国的水果一样糟糕,我们称之为“榴莲”:好吧,就这样吧:)这个实验中一个明显可能的“怪异”是你可以有参考同时在树中的多个位置中的。