我有一棵树。
class TreeNode {
public TreeNode(string name, string description) {
Name = name;
Description = description;
}
string Name { get; set; }
string Description { get; set; }
public List<TreeNode> Children = new List<TreeNode>();
}
我想填充一个大的用于单元测试目的。我真的很喜欢干什么东西。
为了便于说明,我的树具有以下结构
Parent,desc Child 1, desc1 Grandchild 1, desc1 Child 2, desc2
你会如何以优雅和可维护的方式填充树木?
我觉得这段代码非常重复且容易出错:
var parent = new TreeNode("Parent", "desc");
var child1 = new TreeNode("Child 1", "desc1");
var child2 = new TreeNode("Child 2", "desc2");
var grandchild1 = new TreeNode("Grandchild 1", "desc1");
parent.Children.Add(child1);
parent.Children.Add(child2);
child1.Children.Add(grandchild1);
修改
我最终做了DSL方法:
它使用构建器和简单的DSL。
答案 0 :(得分:3)
你可以编写一个带有状态的“TreeBuilder”来保存一些连接混乱:
TreeBuilder builder = new TreeBuilder();
builder.AddNode("Parent", "desc"); // Adds a node, and sets the cursor to it
builder.AddLeaf("Child 1", "desc1"); // Adds a node and leaves the cursor at the Parent
builder.AddNode("Child 2", "desc2");
builder.AddLeaf("Grandchild 1", "desc1");
builder.Up(); // Moves the cursor to the parent
builder.AddNode("Child 3", "desc3");
root = builder.GetRoot()
另一种方法是用一些简单的格式发明一个简单的配置文件/字符串。
答案 1 :(得分:2)
嵌套构造可能是一个很好的选择。不要暴露孩子名单的好主意。
class Program
{
static void Main(string[] args)
{
var parent =
new TreeNode( "Parent", "desc", new TreeNode[] {
new TreeNode( "Child 1", "desc1", new TreeNode[] {
new TreeNode( "Grandchild 1", "desc1" ) } ),
new TreeNode( "Child 2", "desc2" ) } );
}
}
class TreeNode
{
public TreeNode(string name, string description, IEnumerable<TreeNode> children)
: this(name, description)
{
_children.AddRange(children);
}
public TreeNode(string name, string description)
{
Name = name;
Description = description;
}
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<TreeNode> Children
{
get
{
return _children.AsReadOnly();
}
set
{
_children.Clear();
_children.AddRange(value);
}
}
private List<TreeNode> _children = new List<TreeNode>();
}
答案 2 :(得分:2)
理想情况下,您希望有一种方法将语言扩展为自定义类型的文字。 C#没有这个,所以你必须找到另一种方法。
您可以制作内部DSL ,通常使用流畅的界面。
使用自定义解析器创建外部DSL 。如果您仔细设计语言,解析器可以很容易。
使用 XML 。基本上这是一种创建外部DSL并免费获得解析器的方法。
外部DSL选项很不错,因为当你阅读它们时,你知道只有数据,并且不必担心理解代码结构。此外,数据是文件,文件是数据。这样可以通过更改文件轻松交换数据,并且更容易准备好文件更改历史记录。最后,当非程序员提供数据时,外部DSL就很好。
这里的权衡是时间与价值。 您需要提供多少数据/更改频率/更改者是您必须回答的问题。
答案 3 :(得分:1)
您可以使用填充树的简单解析器编写树内容的简单XML表示。以下将给出您在上面指定的结构。
<Node description="desc">
Parent
<Node description="desc1">
Child 1
<Node description="desc1">
Grandchild 1
</Node>
</Node>
<Node description="desc2">
Child 2
</Node>
</Node>
答案 4 :(得分:1)
我会将实现拆分为TreeClass和TreeNodeClass
树类将具有成员变量
TreeNodeClass root
方法
TreeNodeClass addAtRoot(data)
返回他们刚刚创建的节点
TreeNodeClass还需要一个AddChild()方法,它还会返回刚刚添加的节点。
然后你可以做类似
的事情addAtRoot(rootData).AddChild(childData).AddChild(grandchildData);
或
使用类似的东西随机生成树
AddRecursively(TreeNodeClass root)
{
numChildren = SomeRandomNumber;
While(numChildren > 0)
{
CTreeNodeClass newnode = root.AddChild(SomeRandomData);
AddRecursively(newnode);
}
}
主要思想是您想要返回刚刚添加到树中的节点。
你可能也想让孩子知道它的父母,因为这有时非常方便。