从数组中获取generics枚举器
在C#中,如何获得给定数组的generics枚举?
在下面的代码中, 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 // L_0001: ldarg.0 // L_0002: ldfld int32[] agree.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[] agree.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[]
select非通用IEnumerable
接口作为GetEnumerator()
默认(即非显式)实现。
IEnumerator<int> NoGet() // error - do not use { return (IEnumerator<int>)arr.GetEnumerator(); // L_0001: ldarg.0 // L_0002: ldfld int32[] agree.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
inheritance的SZArrayEnumerator
一个内部类,它当前被标记为'sealed' – 因为这将允许(协变)generics枚举器被默认返回?
由于我不喜欢演员,所以稍作更新:
your_array.AsEnumerable().GetEnumerator();
为了让它尽可能的干净,我喜欢让编译器完成所有的工作。 没有演员(所以它实际上是types安全的)。 没有使用第三方库(System.Linq)(没有运行时间开销)。
public static IEnumerable<T> GetEnumerable<T>(this T[] arr) { return arr; }
//并使用代码:
String[] arr = new String[0]; arr.GetEnumerable().GetEnumerator()
这利用了一些编译器的魔力,保持一切干净。
另一点需要注意的是我的答案是编译时检查的唯一答案。
对于任何其他解决scheme,如果“arr”types发生变化,则调用代码将被编译,并在运行时失败,从而导致运行时错误。
我的答案将导致代码不能编译,因此我有更less的机会在我的代码中发送错误,因为它会告诉我,我使用了错误的types。
。YourArray.OfType()的GetEnumerator();
可能会更好一些,因为它只需要检查types,而不是投射。
MyType[] arr = { new MyType(), new MyType(), new MyType() }; IEnumerable<MyType> enumerable = arr; IEnumerator<MyType> en = enumerable.GetEnumerator(); foreach (MyType item in enumerable) { }
当然,你可以做的只是实现你自己的generics枚举数组。
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. */} } }
这或多或less等于Glenn Slayden提到的SZGenericArrayEnumerator <T>的.NET实现。 你当然只能这样做,这是值得的。 在大多数情况下不是。