递归yield方法遍历对象图并返回被访问节点

时间:2014-09-10 14:13:01

标签: c# recursion extension-methods yield-return

我试图编写一个应该遍历对象图并返回所有访问过的对象的扩展方法。

我不确定我的做法是否最好,所以请对此发表评论。产量也在煎我的大脑...我确定答案是显而易见的:/

模型

public class MyClass
{
    public MyClass Parent {get;set;}
}

方式

public static IEnumerable<T> SelectNested<T>
    (this T source, Func<T, T> selector)
    where T : class
{
    yield return source;
    var parent = selector(source);
    if (parent == null)
        yield break;
    yield return SelectNestedParents(parent, selector).FirstOrDefault();
}

用法

var list = myObject.SelectNested(x => x.Parent);

问题

它几乎正常工作。但它只访问2个对象。它是自己和父母。

所以从c -> b -> a开始给出此图c。返回c, b,这不是我想要的。

我正在寻找的结果是b, c

3 个答案:

答案 0 :(得分:2)

SelectNested的最后一行,您只返回第一个父级:

yield return SelectNestedParents(parent, selector).FirstOrDefault();

你必须归还所有父母:

foreach (var p in SelectNestedParents(parent, selector))
  return p;

您可以使用可能更有效的迭代,而不是使用递归:

public static IEnumerable<T> SelectNested<T>(this T source, Func<T, T> selector)
  where T : class {
  var current = source;
  while (current != null) {
    yield return current;
    current = selector(current);
  }
}

答案 1 :(得分:1)

以下代码应按预期工作:

public static IEnumerable<T> SelectNested<T>()
{
    if (source != null){
        yield return source;

        var parent = selector(source);

        // Result of the recursive call is IEnumerable<T>
        // so you need to iterate over it and return its content.
        foreach (var parent in (SelectNested(selector(source))))
        {
            yield return parent;
        }
    }
}

答案 2 :(得分:1)

严格来说,您的类看起来是一个列表,而不是图形,因为selector只返回一个对象,而不是它们的枚举。因此没有必要进行递归。

    public static IEnumerable<T> SelectNested<T>(this T source, Func<T, T> selector)
        where T : class
    {
        while (source != null)
        {
            yield return source;
            source = selector(source);
        }
    }