99

在 C# 中,如何从给定数组中获取泛型枚举数?

在下面的代码中,MyArray是一个MyType对象数组。我想以MyIEnumerator显示的方式获得,但似乎我获得了一个空的枚举器(尽管我已经确认MyArray.Length > 0)。

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

7 回答 7

109

适用于 2.0+:

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

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

myArray.Cast<MyType>().GetEnumerator()   // returns IEnumerator<MyType>
于 2009-08-13T15:21:48.507 回答
60

您可以自己决定强制转换是否丑到足以保证一个无关的库调用:

int[] arr;
IEnumerator<int> Get1()
{
    return ((IEnumerable<int>)arr).GetEnumerator();  // <-- 1 non-local call

    // ldarg.0 
    // ldfld int32[] foo::arr
    // castclass System.Collections.Generic.IEnumerable`1<int32>
    // callvirt instance class System.Collections.Generic.IEnumerator`1<!0> System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
}

IEnumerator<int> Get2()
{
    return arr.AsEnumerable().GetEnumerator();   // <-- 2 non-local calls

    // ldarg.0 
    // ldfld int32[] foo::arr
    // call class System.Collections.Generic.IEnumerable`1<!!0> System.Linq.Enumerable::AsEnumerable<int32>(class System.Collections.Generic.IEnumerable`1<!!0>)
    // callvirt instance class System.Collections.Generic.IEnumerator`1<!0> System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
}

为了完整起见,还应该注意以下内容是不正确的——并且会在运行时崩溃——因为T[]选择泛型IEnumerable接口作为其默认(即非显式)实现的GetEnumerator().

IEnumerator<int> NoGet()                    // error - do not use
{
    return (IEnumerator<int>)arr.GetEnumerator();

    // ldarg.0 
    // ldfld int32[] foo::arr
    // callvirt instance class System.Collections.IEnumerator System.Array::GetEnumerator()
    // castclass System.Collections.Generic.IEnumerator`1<int32>
}

谜团在于,为什么不SZGenericArrayEnumerator<T>从当前标记为“密封”的内部类继承SZArrayEnumerator——因为这将允许默认返回(协变)泛型枚举器?

于 2012-07-31T00:14:36.937 回答
25

由于我不喜欢选角,所以稍微更新一下:

your_array.AsEnumerable().GetEnumerator();
于 2012-04-06T16:10:11.903 回答
6

为了让它尽可能干净,我喜欢让编译器完成所有的工作。没有强制转换(因此它实际上是类型安全的)。不使用第三方库 (System.Linq)(无运行时开销)。

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

// 并使用代码:

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

这利用了一些保持一切干净的编译器魔法。

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

对于任何其他解决方案,如果“arr”的类型发生更改,则调用代码将编译,并在运行时失败,从而导致运行时错误。

我的回答将导致代码无法编译,因此我在代码中出现错误的机会较小,因为它会向我表明我使用了错误的类型。

于 2014-05-30T02:45:05.300 回答
2

YourArray.OfType().GetEnumerator();

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

于 2014-04-04T20:59:43.970 回答
0
    MyType[] arr = { new MyType(), new MyType(), new MyType() };

    IEnumerable<MyType> enumerable = arr;

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

    foreach (MyType item in enumerable)
    {

    }
于 2016-01-11T14:48:47.770 回答
-1

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

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. */}
    }
}

这或多或少等于 Glenn Slayden 提到的 SZGenericArrayEnumerator<T> 的 .NET 实现。您当然应该只这样做,这是值得付出努力的情况。在大多数情况下,它不是。

于 2016-07-16T11:39:06.130 回答