문제

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+에서 작동합니다 (Fancy Linqy, 조금 덜 효율적) :

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 기본값 (예 : 비유물) 구현에 대한 인터페이스 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-현재 '밀봉'으로 표시된 내부 클래스-(Covariant) 일반 열거자를 기본적으로 반환 할 수 있으므로?

캐스팅을 좋아하지 않기 때문에 약간의 업데이트 :

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