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

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

MyType [ ]  MyArray  =  ... ;
IEnumerator<MyType>  MyIEnumerator
  =  ( MyArray.GetEnumerator() as IEnumerator<MyType> ) ;
有帮助吗?

解决方案

在2.0+上工作:

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

在3.5+上工作(花式林奇,效率降低):

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

其他提示

您可以自己决定铸造是否足够丑陋,可以保证一个无关的图书馆电话:

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 其默认(IE不明确)实现的接口 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- 当前标记为“密封”的内部类 - 因为这将允许默认情况下(协变)通用枚举器?

由于我不喜欢铸造,因此一些更新:

your_array.AsEnumerable().GetEnumerator();

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

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

//并使用代码:

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

这利用了一些编译器魔术,使一切都保持清洁。

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

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

我的答案将导致代码没有编译,因此我在代码中运送错误的机会较小,因为这会向我表示我正在使用错误的类型。

yourarray.oftype()。getEnumerator();

可以表现更好一些,因为它只需要检查类型而不需要铸造即可。

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

    IEnumerable<MyType> enumerable = arr;

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

    foreach (MyType item in enumerable)
    {

    }

当然,您可以做的只是为阵列实施自己的通用枚举器即可。

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的.NET植入u003CT>正如格伦·斯莱登(Glenn Slayden)提到的那样。当然,您应该只这样做,这是值得努力的情况。在大多数情况下,不是。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top