c# - 为复合模式的叶节点实现 IEnumerable

标签 c# ienumerable composite

我已经实现了如下的复合模式

public interface IComponent
{
   string Name { get; }
}

public interface IComposite : IComponent
{
    void AddRange(IEnumerable<IComponent> components);
}
public interface ILeaf : IComponent
{
    string Content { get; }
    string Parent { get; }
}

public class Composite : IComposite
{
    // return an iterator?
    private readonly List<IComponent> _children = new List<IComponent>();

    public Composite(string name)
    {
        Name = name;
    }

    public string Name { get; }

    public void AddRange(IEnumerable<IComponent> components)
    {
        _children.AddRange(components);
    }
}

public class Leaf : ILeaf
{
    public string Name { get; }
    public string Content { get; }
    public string Parent { get; }

    public Leaf(string name, string content, string parent)
    {
        Name = name;
        Content = content;
        Parent = parent;
    }
}

我已经从一个 xml 文件中填充了复合 Material ,如下所示

var collection = XElement.Load(@"C:\somexml.xml");
   var composite = CreateComposite(collection);

在哪里

public IComponent CreateComposite(XElement element)
    {
        if (!element.HasElements)
            return new Leaf(element.Name.LocalName, element.Value, element.Parent.Name.LocalName);

        var composite = new Composite(element.Name.LocalName);
        composite.AddRange(element.Elements().Select(CreateComposite));
        return composite;
    }

这按预期填充了我的合成 - 太棒了!但是,我现在希望我的组合通过 IEnumerable 的实现返回一个迭代器。所以我试了一下

public class Composite : IComposite, IEnumerable<IComponent>
{
    // return an iterator?
    private readonly List<IComponent> _children = new List<IComponent>();

    public Composite(string name)
    {
        Name = name;
    }

    public string Name { get; }

    public void AddRange(IEnumerable<IComponent> components)
    {
        _children.AddRange(components);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public IEnumerator<IComponent> GetEnumerator()
    {
        foreach (var child in _children)
        {
            yield return child;
        }
    }
}

但这只会遍历组件的顶层,即不会返回嵌套在 _children 中的任何组件。我如何更新它以递归遍历所有组件?

最佳答案

您可以像这样递归迭代(它将以深度优先的方式进行迭代):

public interface IComposite : IComponent, IEnumerable<IComponent>
{
    void AddRange(IEnumerable<IComponent> components);
}

public IEnumerator<IComponent> GetEnumerator()
{
    foreach (var child in _children)
    {
        yield return child;
        var composite = child as IComposite;
        if (composite != null) {
            foreach (var sub in composite) {
                yield return sub;
            }
        }
     }
}

如果您想避免转换为 IComposite - 您需要重新设计您的界面并使您的 Composite 包含另一个 IComposite 的列表>s 而不是组件。然后 ILeft 也将成为具有虚拟实现的 IComposite

关于c# - 为复合模式的叶节点实现 IEnumerable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43276141/

相关文章:

c# - 将 powershell 变量传递给 PS 脚本中的 C# 代码

java - 复合继承: how to assign a final field at sub-class constructor which depends on 'this' value (backward reference)?

c# - 同步两个枚举

c# - 统一: Are running Coroutines destroyed upon loading new scene?

c# - 如何使用 Linq 查询和 IEnumerable 获取类属性的值

java - 叶节点中具有自定义操作的复合模式

java - Java 中的元泛型

c# - 从 WebAPI IQueryable 中排除列

c# - 如何创建 'Private' ResourceDictionary?

c# - 图钉为空