从数组中获取通用枚举器

时间:2009-08-13 15:21:24

标签: c# arrays generics ienumerator

在C#中,如何从给定数组中获取通用枚举器?

在下面的代码中,MyArrayMyType个对象的数组。我希望以所示的方式获得MyIEnumerator, 但似乎我获得了一个空的枚举器(虽然我已经确认MyArray.Length > 0)。

MyType [ ]  MyArray  =  ... ;
IEnumerator<MyType>  MyIEnumerator
  =  ( MyArray.GetEnumerator() as IEnumerator<MyType> ) ;

7 个答案:

答案 0 :(得分:86)

适用于2.0 +:

((IEnumerable<MyType>)myArray).GetEnumerator()

适用于3.5+(花哨的LINQy,效率稍差):

myArray.Cast<MyType>().GetEnumerator()   // returns IEnumerator<MyType>

答案 1 :(得分:45)

你可以自己决定施放是否足够丑以保证无关的图书馆电话:

int[] arr;
IEnumerator<int> Get1()
{
    return ((IEnumerable<int>)arr).GetEnumerator();    // <-- 1 non-local call
    // L_0001: ldarg.0 
    // L_0002: ldfld int32[] foo::arr
    // L_0007: castclass [mscorlib]System.Collections.Generic.IEnumerable`1<int32>
    // L_000c: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
    // L_0011: stloc.0 
}
IEnumerator<int> Get2()
{
    return arr.AsEnumerable().GetEnumerator();    // <-- 2 non-local calls
    // L_0001: ldarg.0 
    // L_0002: ldfld int32[] foo::arr
    // L_0007: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::AsEnumerable<int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
    // L_000c: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
    // L_0011: stloc.0 
}

为了完整起见,还应注意以下内容不正确 - 并且会在运行时崩溃 - 因为T[]选择 - 通用IEnumerable接口对于GetEnumerator()的默认(即非显式)实现。

IEnumerator<int> NoGet()   // error - do not use
{
    return (IEnumerator<int>)arr.GetEnumerator();
    // L_0001: ldarg.0 
    // L_0002: ldfld int32[] foo::arr
    // L_0007: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Array::GetEnumerator()
    // L_000c: castclass [mscorlib]System.Collections.Generic.IEnumerator`1<int32>
    // L_0011: stloc.0 
}

谜是,为什么SZGenericArrayEnumerator<T>不继承SZArrayEnumerator - 一个当前标记为'密封'的内部类 - 因为这样可以返回(协变)通用枚举器默认情况下?

答案 2 :(得分:21)

因为我不喜欢施法,所以稍微更新一下:

your_array.AsEnumerable().GetEnumerator();

答案 3 :(得分:6)

让它尽可能干净我喜欢让编译器完成所有工作。没有演员表(所以它实际上是类型安全的)。没有使用第三方库(System.Linq)(没有运行时开销)。

    public static IEnumerable<T> GetEnumerable<T>(this T[] arr)
    {
        return arr;
    }

//并使用代码:

    String[] arr = new String[0];
    arr.GetEnumerable().GetEnumerator()

这利用了一些编译器魔法来保持一切清洁。

另一点需要注意的是,我的答案是进行编译时检查的唯一答案。

对于任何其他解决方案,如果&#34; arr&#34;更改,然后调用代码将编译,并在运行时失败,导致运行时错误。

我的回答会导致代码无法编译,因此我在代码中发送错误的可能性较小,因为它会向我发出错误的信息。

答案 4 :(得分:2)

YourArray.OfType()的GetEnumerator();

可能表现得更好,因为它只需要检查类型,而不是强制转换。

答案 5 :(得分:1)

    MyType[] arr = { new MyType(), new MyType(), new MyType() };

    IEnumerable<MyType> enumerable = arr;

    IEnumerator<MyType> en = enumerable.GetEnumerator();

    foreach (MyType item in enumerable)
    {

    }

答案 6 :(得分:0)

当然,你可以做的只是为数组实现你自己的通用枚举器。

using System.Collections;
using System.Collections.Generic;

namespace SomeNamespace
{
    public class ArrayEnumerator<T> : IEnumerator<T>
    {
        public ArrayEnumerator(T[] arr)
        {
            collection = arr;
            length = arr.Length;
        }
        private readonly T[] collection;
        private int index = -1;
        private readonly int length;

        public T Current { get { return collection[index]; } }

        object IEnumerator.Current { get { return Current; } }

        public bool MoveNext() { index++; return index < length; }

        public void Reset() { index = -1; }

        public void Dispose() {/* Nothing to dispose. */}
    }
}

这或多或少等于SZGenericArrayEnumerator&lt; T&gt;的.NET实现。正如Glenn Slayden所说。你当然应该这样做,这是值得努力的情况。在大多数情况下,它不是。