在C#中,如何从给定数组中获取通用枚举器?
在下面的代码中,MyArray
是MyType
个对象的数组。我希望以所示的方式获得MyIEnumerator
,
但似乎我获得了一个空的枚举器(虽然我已经确认MyArray.Length > 0
)。
MyType [ ] MyArray = ... ;
IEnumerator<MyType> MyIEnumerator
= ( MyArray.GetEnumerator() as IEnumerator<MyType> ) ;
答案 0 :(得分:86)
适用于2.0 +:
((IEnumerable<MyType>)myArray).GetEnumerator()
适用于3.5+(花哨的LINQy,效率稍差):
myArray.Cast<MyType>().GetEnumerator() // returns IEnumerator<MyType>
答案 1 :(得分:45)
你可以自己决定施放是否足够丑以保证无关的图书馆电话:
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
- 一个当前标记为'密封'的内部类 - 因为这样可以返回(协变)通用枚举器默认情况下?
答案 2 :(得分:21)
因为我不喜欢施法,所以稍微更新一下:
your_array.AsEnumerable().GetEnumerator();
答案 3 :(得分:6)
让它尽可能干净我喜欢让编译器完成所有工作。没有演员表(所以它实际上是类型安全的)。没有使用第三方库(System.Linq)(没有运行时开销)。
public static IEnumerable<T> GetEnumerable<T>(this T[] arr)
{
return arr;
}
//并使用代码:
String[] arr = new String[0];
arr.GetEnumerable().GetEnumerator()
这利用了一些编译器魔法来保持一切清洁。
另一点需要注意的是,我的答案是进行编译时检查的唯一答案。
对于任何其他解决方案,如果&#34; arr&#34;更改,然后调用代码将编译,并在运行时失败,导致运行时错误。
我的回答会导致代码无法编译,因此我在代码中发送错误的可能性较小,因为它会向我发出错误的信息。
答案 4 :(得分:2)
YourArray.OfType()的GetEnumerator();
可能表现得更好,因为它只需要检查类型,而不是强制转换。
答案 5 :(得分:1)
MyType[] arr = { new MyType(), new MyType(), new MyType() };
IEnumerable<MyType> enumerable = arr;
IEnumerator<MyType> en = enumerable.GetEnumerator();
foreach (MyType item in enumerable)
{
}
答案 6 :(得分:0)
当然,你可以做的只是为数组实现你自己的通用枚举器。
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&lt; T&gt;的.NET实现。正如Glenn Slayden所说。你当然应该这样做,这是值得努力的情况。在大多数情况下,它不是。