C# 遍历对象图并返回访问节点的递归屈服方法

C# 遍历对象图并返回访问节点的递归屈服方法,c#,recursion,extension-methods,yield-return,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> s

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

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

型号

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();
}
问题

它几乎起作用了。但它只访问2个对象。这是我自己和父母

因此,给定这个图,从
c
开始,从
c
开始<代码>c,b返回,这不是我想要的


我要查找的结果是
b,c

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);
  }
}
公共静态IEnumerable SelectNested(此T源,函数选择器)
T:在哪里上课{
无功电流=电源;
while(当前!=null){
产生回流电流;
电流=选择器(电流);
}
}

选择嵌套的最后一行中,您只返回第一个父项:

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);
  }
}
公共静态IEnumerable SelectNested(此T源,函数选择器)
T:在哪里上课{
无功电流=电源;
while(当前!=null){
产生回流电流;
电流=选择器(电流);
}
}

以下代码应按预期工作:

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;
        }
    }
}
public静态IEnumerable SelectNested()
{
如果(源!=null){
收益回报源;
var parent=选择器(源);
//递归调用的结果是IEnumerable
//因此,您需要对其进行迭代并返回其内容。
foreach(在(SelectNested(selector(source)))中的var父对象)
{
收益母公司;
}
}
}

以下代码应按预期工作:

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;
        }
    }
}
public静态IEnumerable SelectNested()
{
如果(源!=null){
收益回报源;
var parent=选择器(源);
//递归调用的结果是IEnumerable
//因此,您需要对其进行迭代并返回其内容。
foreach(在(SelectNested(selector(source)))中的var父对象)
{
收益母公司;
}
}
}

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

    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);
        }
    }
公共静态IEnumerable SelectNested(此T源,函数选择器)
T:在哪里上课
{
while(源!=null)
{
收益回报源;
源=选择器(源);
}
}

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

    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);
        }
    }
公共静态IEnumerable SelectNested(此T源,函数选择器)
T:在哪里上课
{
while(源!=null)
{
收益回报源;
源=选择器(源);
}
}

我喜欢非递归方法。但它应该是
var current=选择器(源)来满足我的需要。谢谢你的帮助@Snæbjørn在您最初的帖子中,您的方法总是返回未经修改的
源代码。这里提供的代码做同样的事情。通过将
current
初始化为
source
,它消除了
yield return source
行,从而简化了代码。这是正确的。然而,产生返回源的唯一原因是因为它是一个递归函数。我真正看到的结果是没有初始对象。正如我在文章最后一行试图解释的:)我喜欢非递归方法。但它应该是
var current=选择器(源)来满足我的需要。谢谢你的帮助@Snæbjørn在您最初的帖子中,您的方法总是返回未经修改的
源代码。这里提供的代码做同样的事情。通过将
current
初始化为
source
,它消除了
yield return source
行,从而简化了代码。这是正确的。然而,产生返回源的唯一原因是因为它是一个递归函数。我真正看到的结果是没有初始对象。正如我试图在帖子的最后一行解释的那样:)