C# 是否可以编写递归IEnumerable<;T>;

C# 是否可以编写递归IEnumerable<;T>;,c#,.net,collections,recursion,ienumerable,C#,.net,Collections,Recursion,Ienumerable,我有一门课,像: class Spline int ChildrenCount; Spline GetChild (int index) class SplineCollection : IEnumerable<Spline> Spline Master 类样条曲线 国际儿童计数; 样条线GetChild(整数索引) 类样条集合:IEnumerable 样条母版 是否可以为SplineCollection编写一个递归IEnumerable,其中它将逐个返

我有一门课,像:

class Spline
    int ChildrenCount;
    Spline GetChild (int index)

class SplineCollection : IEnumerable<Spline>
    Spline Master
类样条曲线
国际儿童计数;
样条线GetChild(整数索引)
类样条集合:IEnumerable
样条母版
是否可以为SplineCollection编写一个递归IEnumerable,其中它将逐个返回所有子对象

编辑:所以Master是根框,其子对象的层次结构可以是任意深度


编辑:通过使用名称框,我想我把一些人弄糊涂了。它应该是一个几何对象,而不是一个容器。因此,将其更改为样条线。

是的-有关使用C迭代器的信息,请参见本节。

这将对
框进行深度优先遍历。然后,您可以在
Master
框中调用此方法以返回所有递归子级

public class Box
{
    // ...

    public IEnumerable<Box> GetBoxes() 
    {
        yield return this;

        for (int i=0; i<box.ChildrenCount; i++)
        {
            foreach (Box child in box.GetChild(i).GetBoxes())
            {
                 yield return child;
            }
        }
    }
}
公共类框
{
// ...
公共IEnumerable GetBox()
{
收益回报这一点;
对于(int i=0;i
类框
{
国际儿童计数;
Box GetChild(int-index){/*一些实现*/}
可数儿童的公共教育
{
得到
{
for(int i=0;i!=ChildrenCount;++i)
收益回报率(i);
}
}
公共数字后裔
{
得到
{
foreach(子对象中的框子对象)
{
退换子女;
foreach(子代中的框描述)
收益率下降;
}
}
}
}
您可以从BoxCollection调用它,但由于Box已经是一个Box的集合,我不知道BoxCollection的用途是什么。因此,让Box实现
IEnumerable
或它的一个后代(
ICollection
IList
)可能会提高其有用性


也可以用迭代的方式而不是递归的方式来实现,这有时会有更好的性能(几乎在编译器没有将递归转化为迭代的任何时候),但递归的可读性更高,通常性能更高。

当然。您甚至不需要BoxContainer,因为box按其名称作为容器存在:

public class Box
{
    private List<Box> myBoxes;

    public IEnumerable<Box> GetAllBoxes()
    {
        yield return this;
        foreach (var box in myBoxes)
        {
            var enumerator = box.GetAllBoxes().GetEnumerator();
            while(enumerator.MoveNext()) 
                yield return enumerator.Current;
        }
    }
}
公共类框
{
私人列表邮箱;
公共IEnumerable GetAllBox()
{
收益回报这一点;
foreach(MyBox中的变量框)
{
var枚举器=box.getAllbox().GetEnumerator();
while(枚举数.MoveNext())
产生返回枚举数。当前;
}
}
}

如果框A包含框B和C,框B包含框D和E,框C包含框F,则可枚举的结果将是A、B、D、E、C、F。

是的,但您必须枚举递归结果。您不能只返回它,因为类型不匹配

IEnumerable<int> Triangle(int n) {
    yield return n;
    if (n > 0)
        foreach (var e in Triangle(n - 1))
            yield return e;
}
IEnumerable三角形(int n){
收益率n;
如果(n>0)
foreach(三角形中的变量e(n-1))
收益率e;
}

我倾向于手动维护堆栈,而不是依赖这里的调用堆栈。原因是,如果通过递归调用获取子体的方法来使用调用堆栈,则必须为访问的每个
样条线创建一个新的
IEnumerable
。这将是低效的。您可以显著提高效率通过使用自己的堆栈改进遍历

public IEnumerable<Spline> Descendants
{
    get
    {
        // This performs a simple iterative preorder traversal.
        var stack = new Stack<Spline>(new Spline[] { this });
        while (stack.Count > 0)
        {
            Spline current = stack.Pop();
            yield return current;
            for (int i = current.ChildrenCount - 1; i >= 0; i--)
            {
                stack.Push(current.GetChild(i));
            }
        }
    }
}
公共IEnumerable子体
{
得到
{
//这将执行一个简单的迭代前序遍历。
var stack=新堆栈(新样条线[]{this});
而(stack.Count>0)
{
样条线电流=stack.Pop();
产生回流电流;
对于(int i=current.ChildrenCount-1;i>=0;i--)
{
stack.Push(current.GetChild(i));
}
}
}
}

这增加了Brian Gideon的伟大答案,只提供了子体,没有根元素。它还使用了
foreach
,例如在EF上下文中可能可用

这是我的代码():

//
///检索所有子代。
/// 
公共数字后裔{
得到{
//这将执行一个简单的迭代前序遍历。
Stack Stack=新堆栈(this.Children);
而(stack.Count>0){
Itemcurrent=stack.Pop();
产生回流电流;
//推电流的孩子们
foreach(current.Children中的项目currentChild){
stack.Push(currentChild);
}
}
}
}

谢谢,但这会通过每个框的子项来完成吗。GetChild(i)也是吗?啊,现在它有意义了。编辑了答案。我认为你写“子项”时是指“后代”,因为获取子对象不需要递归。@Job,是的,你是对的,我指的是后代。只是在我使用的sdk中,它们仍然被称为子对象,ChildrenRecursive,这就是为什么我刚才使用它。你的
foreach
有效地导致返回类型为
IEnumerable
,与声明的ret不匹配urn类型。我不相信这会在C#中编译。在F#中,您可以将第二个
yield
更改为
yield!
,它会工作得很好。您完全正确。快速编辑以迭代子框返回的IEnumerable。我希望我可以投票10次。这比递归解决方案效率更高,只需要几秒钟的思考。事实上,您可以将其概括为一个
flatte
函数来简化任何递归迭代器。这实际上还返回根元素,而不仅仅是实际的后代。
public IEnumerable<Spline> Descendants
{
    get
    {
        // This performs a simple iterative preorder traversal.
        var stack = new Stack<Spline>(new Spline[] { this });
        while (stack.Count > 0)
        {
            Spline current = stack.Pop();
            yield return current;
            for (int i = current.ChildrenCount - 1; i >= 0; i--)
            {
                stack.Push(current.GetChild(i));
            }
        }
    }
}
/// <summary>
///     Retrieves all descendants.
/// </summary>
public IEnumerable<Item> Descendants {
    get {
        // This performs a simple iterative preorder traversal.
        Stack<Item> stack = new Stack<Item>(this.Children);
        while (stack.Count > 0) {
            Itemcurrent = stack.Pop();
            yield return current;

            //Push current's children
            foreach (Item currentChild in current.Children) {
                stack.Push(currentChild);
            }
        }
    }
}