views:

263

answers:

3
 public static IEnumerable<UIElement> Traverse(this UIElementCollection source)
    {
        source.OfType<Grid>().SelectMany(v => Traverse(v.Children));
        //This is the top level.
        foreach (UIElement item in source)
        {
            yield return item;
        }
    }

This never returns anything recursively. I have been around the houses. The Linq chain should call back into the function/extension method but never does. The line does nothing as far as I can tell!

+2  A: 

You are not doing anything with the result of the expression and probably the lazy evaluation is not enforced. If you really want to ignore the result of the expression, at least try adding ToArray() at the end ;) That should enforce the evaluation and recursively call your Traverse function.

Advantage of Bojan's solution (provided that's what you really want because it returns a different result than your initial one), is that the actual evaluation responsibility is shifted to the client of the Traverse method. Because in your case these are in-memory queries anyway, it is not that big of a difference, but if these were database queries there is a more significant performance penalty (count of actual database queries) for putting ToArray somewhere.

Thomas Wanner
I am kind of with you, in that the expression isn't being evaluated. I need it to evaluate. Var t = at the start maybe?
DavidA
var t is not enough, without actually iterating it somewhere or enforcing the evaluation by ToArray() it will still not be evaluated ;)
Thomas Wanner
Good explination so get some points! The ToArray to force execution tagged me onto the fact that i needed to force it. So in the end used the concat and dumped the expression into the outer for loop construct.
DavidA
+2  A: 

The recursive call is never executed, as you never use the result of SelectMany. You can make this method lazy, and let the clients evaluate it when needed by combining the result of SelectMany with the current source. Perhaps something like this would do the job (not tested):

public static IEnumerable<UIElement> Traverse(this UIElementCollection source)
{
    var recursive_result = source.OfType<Grid>().SelectMany(v => Traverse(v.Children));
    return recursive_result.Concat( source.Cast<UIElement>() );
}   
Bojan Resnik
This sent me down the road!
DavidA
A: 
 public static IEnumerable<UIElement> Traverse(this UIElementCollection source)
    {
        //This is the top level.
        foreach (UIElement item in source.OfType<Grid>().SelectMany(v => Traverse(v.Children)).Concat(source.Cast<UIElement>()))
        {
            yield return item;
        }
    }

This has the desired result, not sure it is optimal though!

DavidA