Elegant and maintainable way of populating Tree structures in c#

陌路散爱 提交于 2019-12-06 07:38:33
  • Ideally you want a way to extend the language to literals of custom types. C# doesn't have this, so you have to find another approach.

  • You can fabricate an internal DSL, typically with a fluent interface.

  • Follow the XElement example of functional construction.

  • Create an external DSL with a custom parser. If you design the language carefully, the parser can be easy.

  • Use XML. Basically this is a way to create an external DSL and get the parser for free.

The external DSL options are nice because when you read them, you know there's only data, and don't have to worry about making sense of code constructs. Also, the data is the file, and the file is the data. That makes it easy to swap data around by changing files, and easier to ready file change histories. Finally, and external DSL is good when a non-programmer will be supplying the data.

The tradeoff here is time vs. value. How much data you will have / how often it will change / who will change it are the questions you have to answer.

You can write a "TreeBuilder" with a state to save some connections mess:

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

Another way is to invent a simple configuration file/string with some simple format.

Nested construction could be a good option here. Good idea to not expose the list of children too.

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

You could write up a simple XML representation of the tree contents with a simple parser that populates the tree. The following would give the structure you specified above.

<Node description="desc">
    Parent
    <Node description="desc1">
        Child 1
        <Node description="desc1">
            Grandchild 1
        </Node>
    </Node>
    <Node description="desc2">
        Child 2
    </Node>
</Node>

I would split the implementation into a TreeClass and a TreeNodeClass

The Tree Class would have member variables

TreeNodeClass root

with methods

TreeNodeClass addAtRoot(data) 

Which return the node they just created

The TreeNodeClass Also needs an AddChild() Method, which would also return the node it just added.

Then you can do something like

addAtRoot(rootData).AddChild(childData).AddChild(grandchildData);

or

Use something like this to randomly generate a tree

AddRecursively(TreeNodeClass root)
{
    numChildren = SomeRandomNumber;
    While(numChildren > 0)
    {
       CTreeNodeClass newnode = root.AddChild(SomeRandomData);
       AddRecursively(newnode);
    }
}

The main idea is that you want to return the Node that you just added to the tree.

You might also want to make the child know its parent as that can be quite handy sometimes.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!