使用 LINQ 进行递归控制搜索

Posted

技术标签:

【中文标题】使用 LINQ 进行递归控制搜索【英文标题】:Recursive control search with 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 中这样做有多容易?

【问题讨论】:

【参考方案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,多年来,在我的问题链接中的那种递归搜索中,我已经解决了这个问题。只是想让我的一天更有趣,重新发明***,毕竟是星期五 :) 无论如何谢谢。 与新问题类似:***.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;

【讨论】:

以上是关于使用 LINQ 进行递归控制搜索的主要内容,如果未能解决你的问题,请参考以下文章

使用 Javascript 递归地进行线性搜索

使用 scikit-learn 进行递归特征消除和网格搜索

使用 scikit-learn 进行递归特征消除和网格搜索:DeprecationWarning

使用 scikit-learn 对 SVR 进行递归特征消除和网格搜索

递归 linq 表达式以获取非 NULL 父值?

Linq-to-Sql:递归获取孩子