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[]選択するため、以下は正しくなく、実行時にクラッシュすることに注意する必要があります。IEnumerableGetEnumerator()

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 に答える
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 に答える