【问题标题】:Recursive Linq Function and Yielding递归 Linq 函数和屈服
【发布时间】:2010-01-27 14:25:03
【问题描述】:
 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 链应该回调函数/扩展方法,但永远不会。据我所知,这条线什么也没做!

【问题讨论】:

  • “在房子周围”是什么意思?这是英国俚语吗?
  • 俚语:试着到处找,但没有找到我需要的东西。

标签: linq extension-methods yield-return


【解决方案1】:

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

Bojan 解决方案的优势(前提是您真正想要的,因为它返回的结果与您最初的结果不同)是实际评估责任转移到 Traverse 方法的客户端。因为在您的情况下,无论如何这些都是内存查询,差别不大,但如果这些是数据库查询,则将 ToArray 放在某处会导致更显着的性能损失(实际数据库查询的计数)。

【讨论】:

  • 我同意你的看法,因为表达式没有被评估。我需要它来评估。 Var t = 一开始可能吗?
  • var t 是不够的,如果没有在某处实际迭代它或通过 ToArray() 强制执行评估,它仍然不会被评估;)
  • 很好的解释,所以得到一些积分! ToArray 强制执行将我标记为我需要强制执行的事实。所以最后使用了 concat 并将表达式转储到外部 for 循环结构中。
【解决方案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>() );
}   

【讨论】:

    【解决方案3】:
     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;
            }
        }
    

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

    【讨论】:

      猜你喜欢
      • 2018-11-13
      • 2011-06-16
      • 2018-07-05
      • 1970-01-01
      • 2017-06-07
      • 2014-01-31
      • 1970-01-01
      • 2010-10-07
      • 1970-01-01
      相关资源
      最近更新 更多