Итератор для иерархического класса - PullRequest
0 голосов
/ 18 ноября 2018

У меня есть класс C # для определения иерархии (гораздо более сложный, чем в примере ниже).Класс имеет Parent и, возможно, Children того же класса.

Я пытаюсь написать итератор для объекта верхнего уровня, который позволит мне получить доступ ко всему содержимому в цикле foreach.

class Node
{
    public Node Parent { get; private set; }
    public bool HasParent { get { return (Parent != null); } }
    public string Name { get; private set; }
    public bool IsAnimal { get; set; }
    public bool IsCar { get; set; }
    public List<Node> Children { get; private set; }
    public bool HasChildren { get { return (Children != null); } }

}

Хотите получить доступ следующим образом:

foreach (Node myNode in TopNode.Contents)

Было бы неплохо иметь несколько итераторов для обхода различных типов Children, например:

foreach (Node myNode in TopNode.Animals)

или

foreach (Node myNode in TopNode.Cars)

1 Ответ

0 голосов
/ 18 ноября 2018

Добавьте этот метод к классу Node:

public IEnumerable<Node> DescendantsAndSelf()
{
    yield return this;
    if (Children != null) {
        foreach (Node child in Children) {
            foreach (Node node in child.DescendantsAndSelf()) {
                yield return node;
            }
        }
    }
}

И вам не нужны разные итераторы для разных типов узлов. Просто используйте .Where(...)

var allAnimals = myTopNode.DescendantsAndSelf()
    .Where(n => n.IsAnimal);

Если вы принимаете близко к сердцу предложение @ LasseVågsætherKarlsen и выводите различные типы узлов из абстрактного базового класса Node, тогда вы можете получить животных, набранных как Animal, например:

IEnumerable<Animal> allAnimals = myTopNode.DescendantsAndSelf()
    .OfType<Animal>();

Вы также можете объявить Children как:

public List<Node> Children { get; } = new List<Node>();

Таким образом, Children никогда не будет нулевым, а HasChildren будет реализован как:

public bool HasChildren => Children.Count > 0;

См:

...