【问题标题】:yield return in recursion递归收益率
【发布时间】:2013-09-28 00:41:15
【问题描述】:

我正在尝试创建一个

    IEnumrable<PropertyInfo> 

iv'e 有一个名为 Disassemble 的方法,它递归地迭代抛出给定对象及其属性的所有子对象。

请不要担心 INameValueWrapper 类型的内部包装对象

下面的问题是当我遇到一个类属性时,我也不想对其调用 Disassemble 并将其添加到 IEnumrable 的同一迭代中,调用时不会再次发生 Dissasemble 我在哪里发表评论: // 问题就在这里。

    public static IEnumerable<T> Dissasemble<T>(this object sourceObj) where T : INameValueWrapper
    {
        var properties = sourceObj.GetType().GetProperties();

        foreach (var prop in properties)
        {
            var wrapper = (T)prop.WrapPropertyInfo(sourceObj);
            yield return wrapper;

            if (wrapper is CollectionPropertyInfoWrapper)
            {
                var colWrapper = wrapper as CollectionPropertyInfoWrapper;
                var collection = (IList)colWrapper.Value;

                int index = 0;
                foreach (var item in collection)
                {
                    yield return (T)item.WrapItem(collection, index + 1);
                    index++;
                }
            }
            else
            {
                var propWrapper = wrapper as PropertyInfoWrapper;
                if (!propWrapper.IsPrimitive)
                {
                    var childObject = prop.GetValue(sourceObj);
                    childObject.Dissasemble<T>(); // here is the problem 
                }
            }
        }

        yield break;
    } 

1) 为什么它没有被调用并添加到迭代中?

2) 解决此问题的方法是什么? ,

 i could call childObject.Dissasemble<T>().ToList() 
 and then iterate that collection calling yield return on it's items 
 but that seems like re doing something i already did.

提前致谢。

【问题讨论】:

    标签: c# recursion yield


    【解决方案1】:

    代替

    childObject.Dissasemble<T>(); // here is the problem 
    

    试试

    foreach (var a in childObject.Dissasemble<T>())
    {
     yield return a;
    }
    

    【讨论】:

      【解决方案2】:

      您正在调用该方法,但随后忽略了结果。你可能想要这样的东西:

      foreach (var item in childObject.Disassemble<T>())
      {
          yield return item;
      }
      

      我认为您对 yield return 的作用有点困惑 - 它仅在当前执行方法返回的序列中产生一个值。它不会为某些全局序列添加值。如果您忽略递归 Disassemble 调用返回的值,代码甚至不会执行,因为迭代器块是惰性的。 (它们仅在被要求提供另一个值时才执行代码。)

      另外,您不需要在方法结束时使用yield break;。

      请注意,如果递归深入,则使用迭代器块可能效率低下。这对你来说可能不是问题,但这是需要考虑的事情。请参阅 Wes Dyer 和 Eric Lippert 的帖子。

      【讨论】:

      • 好吧,我认为 Jit 编译器确实知道如何构建全局序列,因为它在原始方法的范围内。
      • @eranotzap:不,这与 JIT 编译器无关。这是关于 C# 语言规则说它应该如何表现。 (例如,您可能想调用该方法但不产生结果。)
      • JitCompiler 不是将方法包装在 IEnumrable 对象中吗?
      • @eranotzap:不,C# 编译器可以。或者更确切地说,它将方法转换为一种状态机。见csharpindepth.com/Articles/Chapter6/…
      猜你喜欢
      • 2011-05-14
      • 2015-04-29
      • 2014-10-20
      • 2019-04-14
      • 2010-12-21
      • 2020-11-20
      • 2012-11-26
      • 2014-03-21
      • 2020-08-04
      相关资源
      最近更新 更多