【问题标题】:Recursive yield method to traverse object graph and return visited nodes遍历对象图并返回访问节点的递归yield方法
【发布时间】:2014-09-10 14:13:01
【问题描述】:

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

我不确定我的方法是否是最好的,所以请对此发表评论。产量也在煎炸我的大脑......我相信答案很明显:/

型号

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 -&gt; b -&gt; ac 开始。 c, b 被返回,这不是我想要的。

我要找的结果是b, c

【问题讨论】:

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


    【解决方案1】:

    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);
      }
    }
    

    【讨论】:

    • 我喜欢非递归的方法。但它应该是var current = selector(source); 来满足我的需求。感谢您的帮助!
    • @Snæbjørn 从您的原始帖子中,您的方法始终返回 source 第一个未修改。这里提供的代码做同样的事情。通过将current 初始化为source,它通过消除yield return source 行使代码更简单。
    • 没错。然而,yield return source 存在的唯一原因是因为它是一个递归函数。我真正看到的结果是没有初始对象。正如我试图在帖子的最后一行解释的那样:)
    【解决方案2】:

    以下代码应按预期工作:

    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;
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      严格来说,你的类看起来是一个列表,而不是一个图表,因为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);
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-01
        • 2012-12-12
        • 2012-03-21
        • 1970-01-01
        • 1970-01-01
        • 2018-08-04
        • 2014-03-10
        相关资源
        最近更新 更多