Узел является частью дерева DOM, Элемент является конкретным типом Узла
, например, <foo> This is Text </foo>
у Вас есть Элемент нечто, (который является также Узлом, поскольку Элемент наследовался Узлу), и текстовый Узел, 'Это - текст', который является ребенком Элемента/Узла нечто
Этот код должен помочь
public static class Extensions
{
public static IEnumerable<T> GetRecursively<T>(this IEnumerable collection,
Func<T, IEnumerable> selector)
{
foreach (var item in collection.OfType<T>())
{
yield return item;
IEnumerable<T> children = selector(item).GetRecursively(selector);
foreach (var child in children)
{
yield return child;
}
}
}
}
Вот пример его использования
TreeView view = new TreeView();
// ...
IEnumerable<TreeNode> nodes = view.Nodes.
.GetRecursively<TreeNode>(item => item.Nodes);
Обновление: В ответ на сообщение Эрика Липперта.
Вот значительно улучшенная версия используя метод, описанный в Все об итераторах .
public static class Extensions
{
public static IEnumerable<T> GetItems<T>(this IEnumerable collection,
Func<T, IEnumerable> selector)
{
Stack<IEnumerable<T>> stack = new Stack<IEnumerable<T>>();
stack.Push(collection.OfType<T>());
while (stack.Count > 0)
{
IEnumerable<T> items = stack.Pop();
foreach (var item in items)
{
yield return item;
IEnumerable<T> children = selector(item).OfType<T>();
stack.Push(children);
}
}
}
}
Я провел простой тест производительности, используя следующую методику тестирования производительности . Результаты говорят сами за себя. Глубина дерева имеет лишь незначительное влияние на производительность второго решения; тогда как производительность быстро снижается для первого решения, что в конечном итоге приводит к StackOverflowException
, когда глубина дерева становится слишком большой.
Я не уверен насчет TreeNodes, но вы можете сделать коллекцию Controls формы IEnumerable, используя System.Linq
и, например,
var ts = (from t in this.Controls.OfType<TextBox>
where t.Name.Contains("fish")
select t);
//Will get all the textboxes whose Names contain "fish"
Извините, что говорю Я не знаю, как сделать это рекурсивным, в голову не приходит.
На основе решения Мриденгрена:
public static IEnumerable<T> GetRecursively<T>(this IEnumerable collection,
Func<T, IEnumerable> selector,
Func<T, bool> predicate)
{
foreach (var item in collection.OfType<T>())
{
if(!predicate(item)) continue;
yield return item;
IEnumerable<T> children = selector(item).GetRecursively(selector, predicate);
foreach (var child in children)
{
yield return child;
}
}
}
var theNodes = treeView1.Nodes.GetRecursively<TreeNode>(
x => x.Nodes,
n => n.Text.Contains("1")).ToList();
Изменить: для BillW
Думаю, вы просите что-то вроде этого.
public static IEnumerable<T> <T,TCollection> GetNodesRecursively(this TCollection nodeCollection, Func<T, TCollection> getSub)
where T, TCollection: IEnumerable
{
foreach (var theNode in )
{
yield return theNode;
foreach (var subNode in GetNodesRecursively(theNode, getSub))
{
yield return subNode;
}
}
}
var all_control = GetNodesRecursively(control, c=>c.Controls).ToList();
Похоже, вы на правильном пути, и в приведенных выше ответах есть несколько хороших идей. Но отмечу, что все эти рекурсивные решения имеют глубокие недостатки.
Предположим, что в рассматриваемом дереве всего n узлов с максимальной глубиной дерева d <= n.
Во-первых, они занимают пространство стека системы в глубине дерева. Если древовидная структура очень глубокая, это может привести к сбою стека и сбою программы. Глубина дерева d равна O (lg n), в зависимости от коэффициента ветвления дерева. В худшем случае - никакого ветвления - только связанный список - и в этом случае дерево с несколькими сотнями узлов разнесет стек.
Во-вторых, вы создаете итератор, который вызывает итератор, который вызывает итератор ... так, чтобы каждый MoveNext () на верхнем итераторе фактически выполнял цепочку вызовов, которая снова является O (d) в Стоимость. Если вы сделаете это на каждом узле, то общая стоимость вызовов составит O (nd), что в худшем случае O (n ^ 2) и в лучшем случае O (n lg n). Вы можете добиться большего, чем оба; нет причин, по которым это не может быть линейным во времени.
Уловка состоит в том, чтобы перестать использовать небольшой хрупкий системный стек, чтобы отслеживать, что делать дальше, и начать использовать стек, выделенный кучей, для явного отслеживания.
Вы должны добавить в свой список чтения статью Уэса Дайера по этому поводу:
https://blogs.msdn.microsoft.com/wesdyer/2007/03/23/all-about-iterators/
Он дает несколько хороших техник в конце для написания рекурсивных итераторов.
хрупкий системный стек, чтобы отслеживать, что делать дальше, и начать использовать выделенный в куче стек для явного отслеживания.Вы должны добавить в свой список чтения статью Уэса Дайера по этому поводу:
https://blogs.msdn.microsoft.com/wesdyer/2007/03/23/all-about-iterators/
Он дает несколько хороших техник в конце для написания рекурсивных итераторов.
хрупкий системный стек, чтобы отслеживать, что делать дальше, и начать использовать выделенный в куче стек для явного отслеживания.Вы должны добавить в свой список чтения статью Уэса Дайера по этому поводу:
https://blogs.msdn.microsoft.com/wesdyer/2007/03/23/all-about-iterators/
Он дает несколько хороших техник в конце для написания рекурсивных итераторов.