【问题标题】:What is the best way to convert an IEnumerator to a generic IEnumerator?将 IEnumerator 转换为通用 IEnumerator 的最佳方法是什么?
【发布时间】:2009-05-06 06:54:12
【问题描述】:

我正在为 C#.NET 3.5 中的自定义 ConfigurationHandler 编写自定义 ConfigurationElementCollection,我希望将 IEnumerator 公开为通用 IEnumerator。

实现这一目标的最佳方法是什么?

我目前正在使用代码:

公共新 IEnumerator GetEnumerator() { var list = new List(); var baseEnum = base.GetEnumerator(); 而(baseEnum.MoveNext()) { var obj = baseEnum.Current 作为 GenericObject; 如果 (obj != null) list.Add(obj); } 返回列表.GetEnumerator(); }

干杯

【问题讨论】:

    标签: c# enumeration ienumerator


    【解决方案1】:

    我不相信框架中有任何内容,但您可以轻松编写一个:

    IEnumerator<T> Cast<T>(IEnumerator iterator)
    {
        while (iterator.MoveNext())
        {
            yield return (T) iterator.Current;
        }
    }
    

    从 LINQ 调用 Enumerable.Cast&lt;T&gt; 然后在结果上调用 GetEnumerator() 是很诱人的——但是如果你的类已经实现了 IEnumerable&lt;T&gt; 并且 T 是一个值类型,那么它就相当于一个空操作,所以GetEnumerator() 调用递归并抛出 StackOverflowException。当foo 绝对是一个不同的 对象(它不会委托回这个对象)时,使用return foo.Cast&lt;T&gt;.GetEnumerator(); 是安全的,否则,您最好使用上面的代码。

    【讨论】:

    • 你不能只从演员表中返回枚举器吗?返回 this.Cast().GetEnumerator();
    • @flq, Jon:我正在做this.Cast&lt;T&gt;().GetEnumerator() 解决方案,在相同的场景中(虽然我是从IEnumerable&lt;T&gt; 派生的),但我遇到了堆栈溢出。
    • @Merlyn:我建议您发布一个简短但完整的示例作为另一个 Stack Overflow 问题。
    • @Jon:您最初的收益回报建议解决了我的问题,就像使用 OfType 一样。但无论如何我都可以发布问题。
    • 使用OfType()来避免栈溢出异常,见bug报告connect.microsoft.com/VisualStudio/feedback/details/713688/…
    【解决方案2】:

    IEnumerable&lt;T&gt; 已经派生自IEnumerable,因此无需进行任何转换。您可以简单地对其进行强制转换...实际上它是隐含的,不需要强制转换。

    IEnumerable<T> enumerable = GetGenericFromSomewhere();
    IEnumerable sadOldEnumerable = enumerable;
    return sadOldEnumerable.GetEnumerator();
    

    使用 LINQ 反之亦然:

    var fancyEnumerable = list.OfType<GenericObject>();
    return fancyEnumerable.GetEnumerator();
    

    【讨论】:

    • 我的错误错过了我的方法定义的通用部分
    • 您混淆了 IEnumerable 和 IEnumerator。 IEnumerable 派生自 IEnumerable,而 IEnumerator 派生自 IEnumerator。说“IEnumerable theEnumerator”没有多大意义,因为可枚举不是枚举器。
    • 强制转换不起作用,因为在父对象中,集合存储在 ArrayList 中。
    • 是的 - 读得太快了。但答案仍然适用。我会修复它以反映正确的类。
    • 它不适用于这种情况: var genericEnumerator = (IEnumerator)new ArrayList { 1 }.GetEnumerator();抛出异常:System.InvalidCastException:无法将“ArrayListEnumeratorSimple”类型的对象转换为“System.Collections.Generic.IEnumerator`1[System.Int32]”类型。
    【解决方案3】:

    您可以使用OfType&lt;T&gt;Cast&lt;T&gt;

    public static IEnumerable Digits()
    {
        return new[]{1, 15, 68, 1235, 12390, 1239};
    }
    
    var enumerable = Digits().OfType<int>();
    foreach (var item in enumerable)
        // var is here an int. Without the OfType<int(), it would be an object
        Console.WriteLine(i);
    

    要获得IEnumerator&lt;T&gt; 而不是IEnumerable&lt;T&gt;,您只需致电GetEnumerator()

    var enumerator = Digits().OfType<int>().GetEnumerator();
    

    【讨论】:

      【解决方案4】:

      我遇到了同样的堆栈溢出问题,其中提到了一些 cmets。在我的情况下,这是因为 GetEnumerator 调用需要对 base.GetEnumerator 进行,否则您将在自己的 GetEnumerator 重新定义中循环。

      这是引发堆栈溢出的代码。 foreach 语句的使用调用了我试图重载的同一个 GetEnumerator 函数:

      public new IEnumerator<T> GetEnumerator()
      {
          foreach (T type in this)
          {
              yield return type;
          }
      }
      

      我最终得到了原始帖子的简化版本,因为您不需要使用列表持有人。

      public class ElementCollection<T> : ConfigurationElementCollection, IList<T>
          ...
          public new IEnumerator<T> GetEnumerator()
          {
              var baseEnum = base.GetEnumerator();
              while (baseEnum.MoveNext())
              {
                  yield return baseEnum.Current as T;
              }
          }
          ...
      }
      

      【讨论】:

        【解决方案5】:

        这对我有用。

        IEnumerator<DataColumn> columnEnumerator = dt.Columns.Cast<DataColumn>().GetEnumerator();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-21
          • 1970-01-01
          • 2010-11-19
          • 2016-05-29
          • 2012-02-29
          • 1970-01-01
          相关资源
          最近更新 更多