Iterating an array of nodes, each of which can have children I've written some C# (7) code to iterate through a Node[], listing all of its nodes in order (i.e. child elements are listed immediately after the parent). 

Each Node is defined as follows,

class Node
{
    public string Name { get; set; }

    public List&lt;Node&gt; Children { get; set; } = new List&lt;Node&gt;();

    public bool HasChildren =&gt; Children.Count &gt; 0;

    public Node(int n)
    {
        Name = $"Node #{n}";
    }

    public Node AddChild(Node n)
    {
        Children.Add(n);
        return this;
    }

    public override string ToString() =&gt; Name;
}


The collection of nodes to be iterated would be,

var nodes = new Node[]
{
    new Node(1),
    new Node(2),
    new Node(3)
        .AddChild(new Node(4))
        .AddChild(new Node(5))
        .AddChild(new Node(6)
            .AddChild(new Node(7)))
        .AddChild(new Node(8)
            .AddChild(new Node(9))
            .AddChild(new Node(10)))
};


...and output for the above would be 10 lines of "Node #", each followed by the number passed to the constructor of each (i.e. 1 to 10, in ascending order). 

The code I've written to perfom the aforementioned task is,

var stack = new Stack&lt;(Node[], int)&gt;();

var i = 0;

while (i &lt; nodes.Length)
{
    WriteLine($"{nodes[i]}");

    if (nodes[i].HasChildren)
    {
        // Stores away the current Node[] and the next index, to return to it once all children are iterated though.
        stack.Push((nodes, i + 1));

        // Makes the child Node[] the iteration target.
        nodes = nodes[i].Children.ToArray();

        // Resets the index to iterate all the children.
        i = 0;

        continue;
    }

    // If the current node is the last in the targeted Node[], and there are parent Node[]s from which this Node[] was switched to in the stack.
    if (i == nodes.Length - 1 &amp;&amp; stack.Count &gt; 0)
    {
        // Pop the stack until the popped Node[] isn't the last element, and assign it to the array being iterated.

        var (_target, _i) = stack.Pop();

        while (stack.Count &gt; 0 &amp;&amp; _i &gt;= _target.Length)
        {
            (_target, _i) = stack.Pop();
        }

        nodes = _target;
        i = _i;

        continue;
    }

    ++i;
}


Do provide me with constructive criticism of my algorithm. 
Does it work for Node[]s of any depth (level of child-ception ;)?
Are there ways in which it can be optimized?

N.B. (T1, T2) is equivalent to a Tuple (see: C# 7's System.ValueTuple)
Collection initializer
You can improve and simplify your code by first tuning the Node.

make it IEnumerable&lt;T&gt; and consequently remove the Children and HasChildren properties because now we can use LINQ's Any
let the Name property take care of the formatting and keep the value clean in a dedicated field
replace AddChild with the Add method to be able to use collection initializer
replace the array with a root node

Example:
public class Node&lt;T&gt; : IEnumerable&lt;Node&lt;T&gt;&gt;
{
    private readonly T _value;

    private readonly List&lt;Node&lt;T&gt;&gt; _children = new List&lt;Node&lt;T&gt;&gt;();

    public Node(T value) =&gt; _value = value;

    public T Value =&gt; _value;

    public string Name =&gt; $&quot;Node #{_value}&quot;;

    public void Add(Node&lt;T&gt; node) =&gt; _children.Add(node);

    public override string ToString() =&gt; Name;

    public IEnumerator&lt;Node&lt;T&gt;&gt; GetEnumerator() =&gt; _children.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() =&gt; GetEnumerator();
}


Enumerator
Now you can improve the algorithm by using the Enumerator. There is no need for any indexes or tuples. What you need to do is to GetEnumerator from each node and MoveNext on it until it is now longer possible to continue or continue from a sub node if it contains Any.
The enumerator will keep the current state allowing you to continue iterating on child nodes and resume from the parent node later that's why you need to re-push the current node back to the stack.
An extension for the Node&lt;T&gt; could look like this:
public static IEnumerable&lt;Node&lt;T&gt;&gt; Flatten&lt;T&gt;(this Node&lt;T&gt; root)
{
    var stack = new Stack&lt;IEnumerator&lt;Node&lt;T&gt;&gt;&gt;();
    stack.Push(root.GetEnumerator()); // start with the root node

    yield return root; // return the root node
    
    while (stack.Any())
    {
        var node = stack.Pop();
        while (node.MoveNext())
        {
            yield return node.Current;
            if (node.Current.Any())
            {
                stack.Push(node); // re-add the node to continue later
                stack.Push(node.Current.GetEnumerator()); // continue from here now
                break; // we'll continue from &quot;node&quot; later, when node.Current is enumerated
            }
        }
    }
}


Example
You can now create nodes like arrays without confusing parenthesess when adding subnodes:
var nodes = new Node&lt;int&gt;(0)
{
    new Node&lt;int&gt;(1),
    new Node&lt;int&gt;(2),
    new Node&lt;int&gt;(3)
    {
        new Node&lt;int&gt;(4),
        new Node&lt;int&gt;(5)
        {
            new Node&lt;int&gt;(6)
            {
                new Node&lt;int&gt;(7)
            },
            new Node&lt;int&gt;(8)
            {
                new Node&lt;int&gt;(9),
                new Node&lt;int&gt;(10)
            },
            new Node&lt;int&gt;(11)
        }
    },
    new Node&lt;int&gt;(12)
};

after flattening it
nodes.Flatten().Select(n =&gt; n.Name).Dump();

you'll get:

Node #0 
Node #1 
Node #2 
Node #3 
Node #4 
Node #5 
Node #6 
Node #7 
Node #8 
Node #9 
Node #10 
Node #11 
Node #12