Recursive Tree Structure Implementation in C#

Hierarchical data structures are essential for building navigation menus, organization charts, and category trees. This article explores several C# implementations to transform flat data lists into recursive tree formats, suitable for JSON APIs, object-oriented models, and UI dropdowns.

1. Generating Recursive JSON Strings

In some legacy systems or specific integration scenarios, you may need to manually construct a JSON representation of a tree. This method uses StringBuilder to recursively nest child nodes within the parent JSON object.

public string GenerateTreeJson(List<MenuSource> source, string parentKey)
{
    var jsonBuilder = new StringBuilder();
    jsonBuilder.Append("[");
    
    var children = source.Where(x => x.ParentId == parentKey).ToList();
    if (children.Any())
    {
        for (int i = 0; i < children.Count; i++)
        {
            var item = children[i];
            // Serialize current item and strip trailing brace to inject children property
            var baseJson = JsonConvert.SerializeObject(item, new JsonSerializerSettings 
            { 
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore 
            });
            
            string nestedJson = baseJson.Substring(0, baseJson.Length - 1) 
                                + $",\"childNodes\":{GenerateTreeJson(source, item.Id)}" 
                                + "}";
            
            jsonBuilder.Append(nestedJson);
            if (i < children.Count - 1) jsonBuilder.Append(",");
        }
    }
    
    jsonBuilder.Append("]");
    return jsonBuilder.ToString();
}

2. Mapping Flat Data to Nested Object Models

A cleaner approach to modern applications invovles mapping flat database records to a recursive model. This maintains type safety and allows the business logic to manipulate the tree as an object graph.

public void PopulateTree(List<NavigationNode> targetList, List<RawRecord> dataSource, Guid? parentId)
{
    var filteredItems = dataSource.Where(node => node.ParentId == parentId).ToList();

    foreach (var record in filteredItems)
    {
        var node = new NavigationNode
        {
            Id = record.Id,
            ParentId = record.ParentId,
            Label = record.Name,
            Path = record.Url,
            OrderIndex = record.SortOrder,
            IsActive = !record.IsDeleted
        };

        targetList.Add(node);
        
        // Recursively find and attach children
        PopulateTree(node.Children, dataSource, record.Id);
    }
}

3. Formatting Hierarchical Data to UI Select Controls

When displaying hierarchical data in a standard HTML <select> element, visual indentation is required to represent depth. This method flattens the tree but adds visual markers like non-breaking spaces and prefixes.

public void CreateIndentedList(List<NavigationNode> flatResult, List<RawRecord> dataSource, Guid? parentId, int level = 0)
{
    var branch = dataSource.Where(x => x.ParentId == parentId)
                           .OrderBy(x => x.SortOrder)
                           .ToList();

    foreach (var item in branch)
    {
        string indent = "";
        for (int depth = 0; depth < level; depth++)
        {
            indent += HttpUtility.HtmlDecode("&nbsp;&nbsp;") + "└ ";
        }

        var entry = new NavigationNode
        {
            Id = item.Id,
            ParentId = item.ParentId,
            Label = $"{indent}{item.Name}",
            Path = item.Url,
            OrderIndex = item.SortOrder
        };

        flatResult.Add(entry);
        
        // Recursive call increasing the depth level
        CreateIndentedList(flatResult, dataSource, item.Id, level + 1);
    }
}

The Navigation Node Model

Below is the data transfer object (DTO) used in the examples above. It includes standard metadata and a recursive collection to hold child elements.

public class NavigationNode
{
    public Guid Id { get; set; }
    public Guid? ParentId { get; set; }
    public string Identifier { get; set; }
    public string Label { get; set; }
    public string Path { get; set; }
    public int OrderIndex { get; set; }
    public bool IsActive { get; set; }
    public string Permissions { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime UpdatedAt { get; set; }
    
    // Recursive collection for child nodes
    public List<NavigationNode> Children { get; set; } = new List<NavigationNode>();
}

Tags: C# Recursion LINQ JSON DataStructures

Posted on Thu, 13 Aug 2026 16:06:44 +0000 by slimjim