【问题标题】:Recursive Iterators递归迭代器
【发布时间】:2012-06-03 22:11:59
【问题描述】:

我在制作可以遍历以下类型数据结构的迭代器时遇到了一些麻烦。

我有一个名为Expression 的类,它有一个数据成员a List<object>

此列表可以有任意数量的子级,其中一些子级可能是其他 Expression 对象。

我想遍历这个结构,并打印出每个非列表对象(当然我确实想打印出列表的元素),但是在进入列表之前,我想返回“开始嵌套”和在我刚刚退出一个列表后,我想返回“结束巢”。

如果我尽可能忽略该类,我可以做到这一点,如果我想要一个子表达式,我只拥有带有 List<object> 项目的 List<object> 对象,但我宁愿取消它,而是使用 @987654325 @s 作为子列表(这将使对对象的操作更容易。我知道我可以在 List<object> 上使用扩展方法,但这不合适(谁想要在他们的列表中使用 Evaluate 方法)不接受任何参数?)。

我用来生成原始迭代器(有效)的代码是:

    public IEnumerator GetEnumerator(){
        return theIterator(expr).GetEnumerator();
    }
    private IEnumerable theIterator(object root) {
        if ((root is List<object>)){
            yield return " begin nest ";
            foreach (var item in (List<object>)root){
                foreach (var item2 in theIterator(item)){
                    yield return item2;
                }
            }
            yield return " end nest ";
        }
        else
            yield return root;
    }

List&lt;object&gt; for 表达式的类型交换不起作用,并导致 stackOverflow 错误。迭代器应该如何实现?

更新:这是交换后的代码:

    public IEnumerator GetEnumerator() {
        return this.GetEnumerator();
    }
    private IEnumerable theIterator(object root) {
        if ((root is Expression)) {
            yield return " begin nest ";
            foreach (var item in (Expression)root) {
                foreach (var item2 in theIterator(item))
                    yield return item2;
            }
            yield return " end nest ";
        }
        else
            yield return root;
    }

【问题讨论】:

  • 您能告诉我们交换后的代码(给出StackOverflowException 的那个)吗?
  • @Douglas,添加代码
  • Expression 中的List&lt;object&gt; 属性的名称是什么?
  • "这个列表可以有任意数量的子元素,其中一些子元素可能是其他 Expression 对象。"列表的其他元素是什么?
  • @AdamMihalcin 只是其他类型的对象。它们继承自我编写的名为 node 的基类(注意:表达式不继承自该类),但我认为这无关紧要(根据我的调试器,在此迭代器块中没有调用任何代码)。

标签: c# recursion iterator


【解决方案1】:

你得到StackOverflowException的原因是

foreach (var item in (Expression)root)

…内部原因:

((Expression)root).GetEnumerator()

…被调用——这是 CLR 枚举在 foreach 循环的每次迭代期间必须分配给 item 变量的对象的方式。

在您的情况下,GetEnumerator() 调用将导致 theIterator 再次为相同的 root 执行,从而进入无限递归。

要解决您的问题,您需要更换:

foreach (var item in (Expression)root)

…与:

foreach (var item in ((Expression)root).expr)

...其中exprList&lt;object&gt; 属性的名称。

【讨论】:

  • 仍然导致stackoverflow异常。
  • 将此修复与Dan Tao’s 结合使用。您的StackOverflowException 有两个原因。
【解决方案2】:

为什么将GetEnumerator() 改为返回this.GetEnumerator()

在我看来,这就是您的堆栈溢出的来源。

尝试让它返回theIterator(this).GetEnumerator()

【讨论】:

  • 在原始版本中,expr 是保存数据的List&lt;object&gt;。由于新的迭代器将在 Expression 上工作,因此我向它传递了一个表达式。
  • +1:StackOverflowException 的另一个原因(虽然我不认为这是唯一的原因)。
  • 第一次你是对的,应该是theIterator(this).GetEnumerator()
  • @soandos:哈,好的。老实说,我对您的实施感到有些困惑;无论如何,我很高兴你明白了!
猜你喜欢
  • 1970-01-01
  • 2012-11-06
  • 2012-10-17
  • 2019-12-10
  • 2016-07-21
  • 2011-11-14
  • 2013-12-01
  • 2013-06-14
相关资源
最近更新 更多