3 回答
TA贡献1856条经验 获得超5个赞
这在严格的类型安全方式中是不可能的,因为类型安全是在编译时确保的,这需要静态声明类型。但是树是在运行时动态构建的,具有不同的节点类型。
要走的路是拥有一个可以是通用的静态节点数据类型。可以从给定的基本数据类型导出不同类型的数据。使用多态来处理它们。即使用具有不同实现的相同方法集。
public class TreeNode<T>
{
public T Data { get; set; }
private List<TreeNode<T>> _children = new List<TreeNode<T>>();
public IEnumerable<TreeNode<T>> Children => _children;
public TreeNode<T> AddChild(T data)
{
var node = new TreeNode<T> { Data = data };
_children.Add(node);
return node;
}
public void VisitPreOrder(Action<T, int> action, int level)
{
action(Data, level);
foreach (TreeNode<T> node in Children) {
node.VisitPreOrder(action, level + 1);
}
}
}
public class Tree<T>
{
public TreeNode<T> Root { get; } = new TreeNode<T>();
public void VisitPreOrder(Action<T, int> action)
{
Root.VisitPreOrder(action, 0);
}
}
现在您可以拥有与树完全无关的数据类:
public class A
{
public int Index { get; set; }
public virtual void PrintLine()
{
Console.WriteLine($"A {Index}");
}
}
public class B : A
{
public override void PrintLine()
{
Console.WriteLine($"B {Index}");
}
}
public class C : B
{
public override void PrintLine()
{
Console.WriteLine($"C {Index}");
}
}
从您的示例创建树结构
TreeNode<A> node;
var tree = new Tree<A>();
tree.Root.Data = new B { Index = 0 }; // NodeClassB
tree.Root.AddChild(new C { Index = 1 }); // __NodeClassC
node = tree.Root.AddChild(new A { Index = 2 }); // __NodeClassA
node.AddChild(new B { Index = 3 }); // ____NodeClassB
node.AddChild(new B { Index = 4 }); // ____NodeClassB
node.AddChild(new A { Index = 5 }); // ____NodeClassA
node = tree.Root.AddChild(new A { Index = 6 }); // __NodeClassA
node.AddChild(new C { Index = 7 }); // ____NodeClassC
tree.Root.AddChild(new B { Index = 8 }); // __NodeClassB
tree.Root.AddChild(new C { Index = 9 }); // __NodeClassC
因为每个数据类型(基类型或派生类型)都做适合其类型的事情,所以您不需要知道它的确切类型。这称为多态。这将打印树结构:
tree.VisitPreOrder((item, level) => {
Console.Write(new string('_', 4 * level));
item.PrintLine();
});
B 0
____C 1
____A 2 ____B
3 ____B
4
________A 5
____A 6
________C 7
____B 8
____C 9
请注意,T在声明Tree<T>andTreeNode<T>类时,您不需要知道具体的数据类型,因为它T是通用的。你也可以声明
var stringTree = new Tree<string>();
var intTree = new Tree<int>();
TA贡献1842条经验 获得超12个赞
您可能正在寻找复合模式,这是一种对树结构建模的常用方法,例如一个文件系统,其中您有一个叶子(文件)和容器(文件夹),而容器可以包含其他容器或叶子本身。
在您的情况下,至少到目前为止您描述的方式要简单一些,因为这些节点之间没有行为差异。所以对于你的结构,节点实际上可以是浅的,你只需要在你的基类中实现组合。这样,您就没有叶子,而只有(不同的)容器。
public abstract class BaseNode
{
public IList<BaseNode> Children
{ get; } = new List<BaseNode>();
}
public class NodeClassA : BaseNode { }
public class NodeClassB : BaseNode { }
public class NodeClassC : BaseNode { }
然后你就可以构建你的结构了。
- 3 回答
- 0 关注
- 192 浏览
添加回答
举报