【问题标题】:Recursive control search with LINQ使用 LINQ 进行递归控制搜索
【发布时间】:2010-09-20 05:11:27
【问题描述】:

如果我想在 ASP.NET 页面上找到选中的复选框,我可以使用以下 LINQ 查询。

var checkBoxes = this.Controls
                     .OfType<CheckBox>()
                     .TakeWhile<CheckBox>(cb => cb.Checked);

如果复选框嵌套在当前控件集合中,这很好,但我想知道如何通过深入到顶级控件的控件集合来扩展搜索。

问题是在这里提出的:

Finding controls that use a certain interface in ASP.NET

并且收到了非 LINQ 的答案,我已经有了自己的类型和 ID 的递归控制搜索版本作为扩展方法,但我只是想知道在 LINQ 中这样做有多容易?

【问题讨论】:

    标签: asp.net .net-3.5 c#-3.0 linq-to-objects


    【解决方案1】:

    从递归中检查类型/ID,所以只需一个“递归地给我所有控件”的方法,例如

    public static IEnumerable<Control> GetAllControls(this Control parent)
    {
        foreach (Control control in parent.Controls)
        {
            yield return control;
            foreach(Control descendant in control.GetAllControls())
            {
                yield return descendant;
            }
        }
    }
    

    这有点低效(在创建大量迭代器方面),但我怀疑你会有一个 非常 深的树。

    然后您可以将原始查询编写为:

    var checkBoxes = this.GetAllControls()
                         .OfType<CheckBox>()
                         .TakeWhile<CheckBox>(cb => cb.Checked);
    

    (编辑:将 AllControls 更改为 GetAllControls 并正确使用它作为方法。)

    【讨论】:

    • 这行得通,但是如果您使用第三方控件和您自己的服务器控件,就像我们在当前工作场所中所做的那样,您可以获得很好的几级控件嵌套。我想 ASP.NET 页面只是一个更普遍问题的示例,即在 Linq 中向下钻取嵌套集合。
    • 我以前只使用过这种技术。 (如果你想变得非常甜蜜,你可以使用 Y Combinator 将其作为一个表达式来实现!)顺便说一句,AllControls 不应该用作方法吗?
    • @Phil:是的,它可能会下降几个级别并且效率会有点低 - 但你有理由相信这将是一个显着的瓶颈吗?先做最简单的事情,如果真的有问题,再优化。 (例如,单个数据库调用可能会超过此成本。)
    • @Jon,多年来,在我的问题链接中的那种递归搜索中,我已经解决了这个问题。只是想让我的一天更有趣,重新发明轮子,毕竟是星期五 :) 无论如何谢谢。
    • 与新问题类似:stackoverflow.com/questions/3419159/… -- 我很想知道使用Descendants LINQ 函数进行递归控制选择的正确方法。 (也许也更新这个问题/答案?)
    【解决方案2】:

    我对 AllControls 递归的建议是:

        public static IEnumerable<Control> AllControls(this Control parent)
        {
            foreach (Control control in parent.Controls)
            {
                 yield return control;
            }
            foreach (Control control in parent.Controls)
            {
                foreach (Control cc in AllControls(control)) yield return cc;
            }
        }
    

    第二个foreach 看起来很奇怪,但这是我所知道的“展平”递归调用的唯一方法。

    【讨论】:

      【解决方案3】:
      public static IEnumerable<Control> AllControls(this Control container)
      {
          //Get all controls
          var controls = container.Controls.Cast<Control>();
      
          //Get all children
          var children = controls.Select(c => c.AllControls());
      
          //combine controls and children
          var firstGen = controls.Concat(children.SelectMany(b => b));
      
          return firstGen;
      }
      

      现在基于上面的函数,我们可以做这样的事情:

      public static Control FindControl(this Control container, string Id)
      {
          var child = container.AllControls().FirstOrDefault(c => c.ID == Id);
          return child;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-30
        • 2018-07-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多