Вам нужна реализация алгоритма обхода.
Есть несколько из них, либо рекурсивные, либо нерекурсивные. Это зависит от ваших конкретных вариантов использования, какой из них выбрать.
Например, нерекурсивный, ленивый обход ширины:
public static class TreeVisitor
{
public static IEnumerable<TNodeType> WidthTraversal<TNodeType>(TNodeType root, Func<TNodeType, IEnumerable<TNodeType>> getChildNodesFunc)
where TNodeType : class
{
if (root == null)
{
throw new ArgumentNullException(nameof(root));
}
if (getChildNodesFunc == null)
{
throw new ArgumentNullException(nameof(getChildNodesFunc));
}
var visited = new HashSet<TNodeType>();
var queue = new Queue<TNodeType>();
yield return root;
visited.Add(root);
queue.Enqueue(root);
while (queue.Count > 0)
{
var parent = queue.Dequeue();
foreach (var child in getChildNodesFunc(parent))
{
if (child == default(TNodeType))
continue;
if (!visited.Contains(child))
{
yield return child;
visited.Add(child);
queue.Enqueue(child);
}
}
}
}
}
Использование:
var rootItem = new Items
{
Name = "Root",
Children = new List<Items>
{
new Items { Name = "Child1" },
new Items { Name = "Child2" },
// etc
}
};
foreach (var item in TreeVisitor.WidthTraversal(rootItem, _ => _.Children))
{
// ...
}