Reason for my vote of 5
Perfect if you don't care whether you've already examined the parent object. If you're coming from the export to excel page, however, you will need to use a recursive approach or some other method to make sure you're not doing unnecessary work to an object that should already have been removed from the stream.
The code has undergone several revisions and optimizations.
The original code made by rj45 used an additional function named 'GetSubControls'. The latest revision of the code, (from my hand, for which rj45 is yet still to credit or thank me) no longer needs this function.
Check out Alternative1 which gives you the option to go dept-first or width first, depending on your needs.
It adds a control to a list and adds the child controls of that control to the same list, there's no finding or flattening of a hierarchy involved as a control hierarchy can easily extend to over ten levels deep.
By it's design it's a nested for loop which can't locate any controls deeper in the hierarchy than the first child, due to it not being recursive.
It's tagged with recursion and yield, yet contains neither.
I suggest you try it out. I hint may be that it wouldn't work with foreach.
New fangled in regards to not needed recursion, yield, Ienumerable/foreach, Linq, templates. These things are not crap by themselves of course nor new things. They are simply not great IMHO for this simple context. I always laugh when I see the use of things to eliminate a loop or two thats why I posted this.