Рекурсивный поиск с помощью LINQ

Если бы я хотел найти отмеченные флажки на странице ASP.NET, я мог бы использовать следующий запрос LINQ.

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

Это отлично работает, если флажки вложены в текущую коллекцию управления, но я хотел бы знать, как расширить поиск, свернув в контрольные коллекции элементов верхнего уровня.

Здесь был задан вопрос:

Поиск элементов управления, использующих определенный интерфейс в ASP.NET

И получил ответы, отличные от LINQ, у меня уже есть своя версия рекурсивного поиска контроля по типу и идентификатору в качестве методов расширения, но мне просто интересно, как это легко сделать в LINQ?

Возьмите проверку типа / идентификатора рекурсии, так что просто попросите «дать мне все методы управления, рекурсивно», например

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

Это несколько неэффективно (с точки зрения создания множества iteratorов), но я сомневаюсь, что у вас будет очень глубокое дерево.

Затем вы можете написать свой первоначальный запрос:

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

(EDIT: изменено AllControls на GetAllControls и использовать его как метод.)

 public static IEnumerable AllControls(this Control container) { //Get all controls var controls = container.Controls.Cast(); //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; } 

Мое предложение сделать рекурсивные AllControls :

  public static IEnumerable 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 выглядит странно, но это единственный способ, которым я знаю, «сгладить» рекурсивный вызов.

Давайте будем гением компьютера.