배열에서 일반 열거자를 얻습니다
-
13-09-2019 - |
문제
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이 언급했듯이. 물론 그렇게해야합니다. 이것이 노력할만한 가치가있는 경우입니다. 대부분의 경우 그렇지 않습니다.