C# 从数组中获取通用枚举器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1272673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
obtain generic enumerator from an array
提问by JaysonFix
In C#, how does one obtain a generic enumerator from a given array?
在 C# 中,如何从给定数组中获取通用枚举数?
In the code below, MyArray
is an array of MyType
objects. I'd like to obtain MyIEnumerator
in the fashion shown,
but it seems that I obtain an empty enumerator (although I've confirmed that MyArray.Length > 0
).
在下面的代码中,MyArray
是一个MyType
对象数组。我想以MyIEnumerator
显示的方式获得,但似乎我获得了一个空的枚举器(尽管我已经确认了这一点MyArray.Length > 0
)。
MyType[] MyArray = ... ;
IEnumerator<MyType> MyIEnumerator = MyArray.GetEnumerator() as IEnumerator<MyType>;
采纳答案by Mehrdad Afshari
Works on 2.0+:
适用于 2.0+:
((IEnumerable<MyType>)myArray).GetEnumerator()
Works on 3.5+ (fancy LINQy, a bit less efficient):
适用于 3.5+(花哨的 LINQy,效率稍低):
myArray.Cast<MyType>().GetEnumerator() // returns IEnumerator<MyType>
回答by greenoldman
Since I don't like casting, a little update:
由于我不喜欢投射,所以稍微更新一下:
your_array.AsEnumerable().GetEnumerator();
回答by Glenn Slayden
You can decide for yourself whether casting is ugly enough to warrant an extraneous library call:
你可以自己决定强制转换是否丑陋到足以保证一个无关的库调用:
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()
}
And for completeness, one should also note that the following is not correct--and will crash at runtime--because T[]
chooses the non-generic IEnumerable
interface for its default (i.e. non-explicit) implementation of GetEnumerator()
.
并且为了完整性,还应该注意以下内容是不正确的——并且会在运行时崩溃——因为T[]
选择了非通用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>
}
The mystery is, why doesn't SZGenericArrayEnumerator<T>
inherit from SZArrayEnumerator
--an internal class which is currently marked 'sealed'--since this would allow the (covariant) generic enumerator to be returned by default?
谜团是,为什么不SZGenericArrayEnumerator<T>
从SZArrayEnumerator
当前标记为“密封”的内部类继承——因为这将允许默认情况下返回(协变)泛型枚举器?
回答by Andrew Dennison
YourArray.OfType().GetEnumerator();
YourArray.OfType().GetEnumerator();
may perform a little better, since it only has to check the type, and not cast.
性能可能会好一点,因为它只需要检查类型,而不是强制转换。
回答by leat
To Make it as clean as possible I like to let the compiler do all of the work. There are no casts (so its actually type-safe). No third party Libraries (System.Linq) are used (No runtime overhead).
为了使它尽可能干净,我喜欢让编译器完成所有工作。没有强制转换(所以它实际上是类型安全的)。不使用第三方库 (System.Linq)(无运行时开销)。
public static IEnumerable<T> GetEnumerable<T>(this T[] arr)
{
return arr;
}
// And to use the code:
// 并使用代码:
String[] arr = new String[0];
arr.GetEnumerable().GetEnumerator()
This takes advantage of some compiler magic that keeps everything clean.
这利用了一些保持一切干净的编译器魔法。
The other point to note is that my answer is the only answer that will do compile-time checking.
另一点要注意的是,我的答案是唯一可以进行编译时检查的答案。
For any of the other solutions if the type of "arr" changes, then calling code will compile, and fail at runtime, resulting in a runtime bug.
对于任何其他解决方案,如果“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.
我的回答将导致代码无法编译,因此我在代码中发布错误的机会较小,因为它会向我发出信号,表明我使用了错误的类型。
回答by Maxim Q
MyType[] arr = { new MyType(), new MyType(), new MyType() };
IEnumerable<MyType> enumerable = arr;
IEnumerator<MyType> en = enumerable.GetEnumerator();
foreach (MyType item in enumerable)
{
}
回答by Corniel Nobel
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.
这或多或少等于 Glenn Slayden 提到的 SZGenericArrayEnumerator<T> 的 .NET 实现。您当然应该只这样做,这是值得付出努力的情况。在大多数情况下并非如此。