배열에서 일반 열거자를 얻습니다.
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 이상에서 작동합니다 (멋진 LINQy, 약간 덜 효율적) :
myArray.Cast<MyType>().GetEnumerator() // returns IEnumerator<MyType>
캐스팅이 외부 라이브러리 호출을 보증하기에 충분히 추악한 지 스스로 결정할 수 있습니다.
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[]
선택하는 비 -generic 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
것입니다.
캐스팅을 좋아하지 않기 때문에 약간의 업데이트가 있습니다.
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"유형이 변경되면 호출 코드가 컴파일되고 런타임에 실패하여 런타임 버그가 발생합니다.
My answer will cause the code to not compile and therefore I have less chance of shipping a bug in my code, as it would signal to me that I am using the wrong type.
YourArray.OfType().GetEnumerator();
may perform a little better, since it only has to check the type, and not cast.
MyType[] arr = { new MyType(), new MyType(), new MyType() };
IEnumerable<MyType> enumerable = arr;
IEnumerator<MyType> en = enumerable.GetEnumerator();
foreach (MyType item in enumerable)
{
}
What you can do, of course, is just implement your own generic enumerator for arrays.
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. */}
}
}
This is more or less equal to the .NET implemenation of SZGenericArrayEnumerator<T> as mentioned by Glenn Slayden. You should of course only do this, is cases where this is worth the effort. In most cases it is not.
참고URL : https://stackoverflow.com/questions/1272673/obtain-generic-enumerator-from-an-array
'programing' 카테고리의 다른 글
take (1) 대 first () (0) | 2020.09.24 |
---|---|
Visual Studio 2017은 빌드 및 디버깅 중에 너무 느립니다. (0) | 2020.09.24 |
OpenGL 좌표계는 왼손잡이입니까, 오른 손잡이입니까? (0) | 2020.09.24 |
원격 푸시 알림은 Info.plist에 UIBackgroundModes를 추가해야합니까? (0) | 2020.09.23 |
이 WCF 오류의 의미 : "사용자 지정 도구 경고 : wsdl : portType을 가져올 수 없습니다." (0) | 2020.09.23 |