Building tree structure based on flat objects You can find here a Follow-up question

Description

A List&lt;UnrelatedObects&gt; is returned by a 3rd party webservice, which will then be transformed to a List&lt;ArchiveDefinition&gt;. These ArchiveDefinition objects are connected by Parent'.ArchiveNodeId == 'Child'.ParentId.

The root objects TypeOfArchive property will always have the value ArchiveType.Archive.

The goal of the given class below is to build a List&lt;ArchiveTreeNode&gt; of these flat object list to fill a treeview control.  

The class in question

public class ArchiveBuilder
{
    public static List&lt;ArchiveTreeEntry&gt; Build(List&lt;ArchiveDefinition&gt; entries)
    {
        List&lt;ArchiveTreeEntry&gt; rootArchiveTreeEntries = new List&lt;ArchiveTreeEntry&gt;();

        if (entries != null &amp;&amp; entries.Count &gt; 0)
        {
            List&lt;ArchiveDefinition&gt; rootEntries = GetRootEntries(entries);

            foreach (ArchiveDefinition definition in rootEntries)
            {
                rootArchiveTreeEntries.Add(new ArchiveTreeEntry(definition));
                entries.Remove(definition);
            }

            foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
            {
                FillChildren(parent, entries);
            }
        }
        return rootArchiveTreeEntries;
    }

    private static void FillChildren(ArchiveTreeEntry parent,
                                     List&lt;ArchiveDefinition&gt; entries)
    {
        if (entries.Count &gt; 0)
        {
            List&lt;ArchiveDefinition&gt; children = GetChildren(entries, parent.Id);

            if (children.Count &gt; 0)
            {
                RemoveChildren(entries, parent.Id);

                foreach (ArchiveDefinition child in children)
                {
                    ArchiveTreeEntry treeEntryChild = new ArchiveTreeEntry(child);
                    parent.AddChild(treeEntryChild);
                    FillChildren(treeEntryChild, entries);
                }
            }
        }
    }

    private static List&lt;ArchiveDefinition&gt; GetRootEntries(List&lt;ArchiveDefinition&gt; entries)
    {
        return entries.FindAll(e =&gt; e.TypeOfArchive == ArchiveType.Archive);
    }

    private static List&lt;ArchiveDefinition&gt; GetChildren(List&lt;ArchiveDefinition&gt; entries, string parentID)
    {
        return entries.FindAll(e =&gt; e.ParentId == parentID);
    }

    private static void RemoveChildren(List&lt;ArchiveDefinition&gt; entries, string parentID)
    {
        entries.RemoveAll(e =&gt; e.ParentId == parentID);
    }
}


Related classes and enums  

public class ArchiveDefinition
{
    public string ArchiveNodeId { get; private set; }
    public string ParentId { get; private set; }
    public ArchiveType TypeOfArchive { get; private set; }

    public ArchiveDefinition (String parentId, String archiveNodeId,
                              ArchiveType type)
    {
        ParentId = parentId;
        TypeOfArchive = type;
        ArchiveNodeId = archiveNodeId;
    }
}

public enum ArchiveType
{
    Archive, ArchiveGroup, ArchiveEntry
}

public class ArchiveTreeEntry
{
    public ArchiveType ArchiveEntryType { get; private set; }
    public string Id { get; private set; }
    public ReadOnlyCollection&lt;ArchiveTreeEntry&gt; Children
    {
        get
        {
            return new ReadOnlyCollection&lt;ArchiveTreeEntry&gt;(mChildren);
        }
    }

    private List&lt;ArchiveTreeEntry&gt; mChildren = new List&lt;ArchiveTreeEntry&gt;();
    public ArchiveTreeEntry(ArchiveDefinition archiveDefinition)
    {
        Id = archiveDefinition.ArchiveNodeId;
        ArchiveEntryType = archiveDefinition.TypeOfArchive;
    }

    internal void AddChild(ArchiveTreeEntry child)
    {
        if (child != null)
        {
            mChildren.Add(child);
        }
    }
}


I would like to get a review for the ArchiveBuilder class. If you also want to review the related classes and enums, I won't mind.
You could use the AddRange combined with the Except method inside of Build:

public static List&lt;ArchiveTreeEntry&gt; Build(List&lt;ArchiveDefinition&gt; entries)
{
    List&lt;ArchiveTreeEntry&gt; rootArchiveTreeEntries = new List&lt;ArchiveTreeEntry&gt;();

    if (entries != null &amp;&amp; entries.Count &gt; 0)
    {
        List&lt;ArchiveDefinition&gt; rootEntries = GetRootEntries(entries);

        entries = rootArchiveTreeEntried.AddRange(rootEntries.Select(definition=&gt; new ArchiveTreeEntry(definition)).Except(entries);

        foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
        {
            FillChildren(parent, entries);
        }
    }
    return rootArchiveTreeEntries;
}

You have made the public method static, which in this case is probably fine but it does make it harder to unit test dependencies. I envisage the class being consumed, like this:

in app

var builder = new ArchiveBuilder();  
builder.Build(entities);

That said, the private methods are fine as static methods because the are an implementation detail.
The private methods can return/accept IEnumerable&lt;&gt; instead of List&lt;&gt;
From there, you could then re-write the method above to be:

public static List&lt;ArchiveTreeEntry&gt; Build(List&lt;ArchiveDefinition&gt; entries)
{
    List&lt;ArchiveTreeEntry&gt; rootArchiveTreeEntries = new List&lt;ArchiveTreeEntry&gt;();

    if (entries != null &amp;&amp; entries.Count &gt; 0)
    {
        entries = rootArchiveTreeEntried.AddRange(GetRootEntries(entries).Select(entry =&gt; new ArchiveTreeEntry(definition)).Except(entries);

        foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
        {
            FillChildren(parent, entries);
        }
    }
    return rootArchiveTreeEntries;
}


So here is the completely re-written class: 

public class ArchiveBuilder
{
    public IEnumerable&lt;ArchiveTreeEntry&gt; Build(IEnumerable&lt;ArchiveDefinition&gt; entries)
    {
        IEnumerable&lt;ArchiveTreeEntry&gt; rootArchiveTreeEntries = new List&lt;ArchiveTreeEntry&gt;();

        if (entries != null &amp;&amp; entries.Count &gt; 0)
        {
            entries = rootArchiveTreeEntried.AddRange(GetRootEntries(entries).Select(entry =&gt; new ArchiveTreeEntry(definition)).Except(entries);

            foreach (ArchiveTreeEntry parent in rootArchiveTreeEntries)
            {
                FillChildren(parent, entries);
            }
        }
        return rootArchiveTreeEntries;
    }

    private static void FillChildren(ArchiveTreeEntry parent,
                                 IEnumerable&lt;ArchiveDefinition&gt; entries)
    {
        if (entries.Count &gt; 0)
        {
            IEnumerable&lt;ArchiveDefinition&gt; children = GetChildren(entries, parent.Id);

            if (children.Count &gt; 0)
            {
                RemoveChildren(entries, parent.Id);

                foreach (ArchiveDefinition child in children)
                {
                    ArchiveTreeEntry treeEntryChild = new ArchiveTreeEntry(child);
                    parent.AddChild(treeEntryChild);
                    FillChildren(treeEntryChild, entries);
                }
            }
        }
    }

    private static IEnumerable&lt;ArchiveDefinition&gt; GetRootEntries(IEnumerable&lt;ArchiveDefinition&gt; entries)
    {
        return entries.FindAll(e =&gt; e.TypeOfArchive == ArchiveType.Archive);
    }

    private static IEnumerable&lt;ArchiveDefinition&gt; GetChildren(IEnumerable&lt;ArchiveDefinition&gt; entries, string parentID)
    {
        return entries.FindAll(e =&gt; e.ParentId == parentID);
    }

    private static void RemoveChildren(IEnumerable&lt;ArchiveDefinition&gt; entries, string parentID)
    {
        entries.RemoveAll(e =&gt; e.ParentId == parentID);
    }
}



NB: I haven't compiled the class or tested it, so it might not work out the box.