递归Linq函数和屈服

时间:2010-01-27 14:25:03

标签: linq extension-methods yield-return

 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;
        }
    }

这永远不会递归返回任何内容。我一直在房子周围。 Linq链应该回调函数/扩展方法,但永远不会。就我所知,这条线无能为力!

3 个答案:

答案 0 :(得分:2)

您没有对表达式的结果做任何事情,并且可能不会强制执行延迟评估。如果你真的想忽略表达式的结果,至少尝试在最后添加ToArray();)这应该强制执行评估并递归调用你的Traverse函数。

Bojan解决方案的优势(假设您真正想要的是因为它返回的结果与初始结果不同),实际评估职责是转移到Traverse方法的客户端。因为在你的情况下这些都是内存中的查询,它并没有那么大的区别,但如果这些是数据库查询,那么将ToArray放在某处会有更显着的性能损失(实际数据库查询的数量)。

答案 1 :(得分:2)

永远不会执行递归调用,因为您从不使用SelectMany的结果。 您可以使此方法变得懒惰,并让客户在需要时对其进行评估 将SelectMany的结果与当前来源相结合。也许这样的事情可以完成工作(未经测试):

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>() );
}   

答案 2 :(得分:0)

 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;
        }
    }

这有所期望的结果,但不确定它是否是最佳的!