传递给方法时,List.Enumerator不更新 [英] List.Enumerator not updated when passed to method
问题描述
我有一个方法,该方法以IEnumerator<T>
作为参数,迭代一些项目,然后返回结果.我的基础类型是List<T>
.如果我将List<T>.GetEnumerator
的结果用作参数,则每次调用我的方法后,迭代器似乎都不会更新.如果使用IEnumerable<T>.GetEnumerator
,一切正常.这是一些演示该问题的示例代码:
static void Main(string[] args) { var myData = new List<char> { ''a'', ''b'', ''c'', ''d'' }; // This returns type List<char>.Enumerator var listEnum = myData.GetEnumerator(); Console.WriteLine("Using List<char>.GetEnumerator():"); for(Int32 i = 0; i < myData.Count; i++) { WriteEnumerator(listEnum); } Console.WriteLine("Using IEnumerable<char>.GetEnumerator():"); // This returns type IEnumerator<char> var iEnum = ((ICollection<char>)myData).GetEnumerator(); for (Int32 i = 0; i < myData.Count; i++) { WriteEnumerator(iEnum); } Console.WriteLine("Press any key to close"); Console.ReadKey(); } private static void WriteEnumerator(IEnumerator<char> listEnum) { listEnum.MoveNext(); Console.WriteLine(listEnum.Current); }
第一个循环输出
a a a a
第二个循环输出
a b c d
有什么想法为什么这两个有不同的行为?我尝试在.NET源代码中查找List< t> ;,并且GetEnumerator
的两个实现均返回List<T>.Enumerator
,所以我看不出它们为什么会有不同的表现.
至于为什么我不使用IEnumerator
的foreach循环,一位同事和我已经在IEnumerator< byte>上实现了一些扩展方法.像GetNextInt16(),GetNextDouble(),GetNextUInt32()这样可以使我们的代码更整洁. c8>有不同的类型.查看MSDN的文档,了解 List< T> .Enumerator 的返回值类型. [ ^ ]是System.Collections.Generic.List<T>.Enumerator [ System.Collections.Generic.IEnumerator< T> a> [ ^ ],这是一个interface
.
回复OP的评论:
dybs写道:List.GetEnumerator和显式接口实现都只是返回了新的Enumerator(this);
我同意这两种方法都指向该代码.但是,ICollection<T>
从IEnumerable<T>
继承了其GetEnumerator
方法.如果查看该接口的源代码,可以看到存在一种类型为IEnumerator<T>
的方法.因此,基本上,发生的是,对于iEnum
,您将struct(这是一种值类型)装箱到引用类型,而对于listEnum
,该值是一个结构,因为您正在调用IEnumerable<T>
的接口声明
公共 界面 IEnumerable< T> :IEnumerable
{
/// < >
/// 返回遍历集合的枚举数.
/// < /summary >
/// < 返回 >
/// 一个< 请参阅 cref ="T:System.Collections.Generic.IEnumerator` 1" / /// < /返回 >
/// < 过滤器优先级 > 1 < >
IEnumerator< T> GetEnumerator();
}
您可能还会发现此帖子 [
The first loop outputs
a
a
a
a
The second loop outputs
a
b
c
d
Any ideas why these two have different behavior? I tried looking at the .NET source for List<t>, and both implementations of GetEnumerator
return a List<T>.Enumerator
, so I don''t see why they would behave differently.
As for why I''m not using a foreach loop with the IEnumerator
, a colleague and I have implemented some extension method on IEnumerator<byte> like GetNextInt16(), GetNextDouble(), GetNextUInt32() that help make our code cleaner.I tried to debug your code and noticed that
listEnum
and iEnum
have different types. Looking at MSDN''s documentation, the type of return value for List<T>.Enumerator[^] is System.Collections.Generic.List<T>.Enumerator[^], which is a struct
. So every time you call the method, you pass a new copy to it, and that only the copy gets updated. On the other hand, iEnum
has a type of System.Collections.Generic.IEnumerator<T>[^], which is an interface
.
[Edit]In reply to comment of OP:
dybs wrote:both List.GetEnumerator and the explicit interface implementation were simply return new Enumerator(this);
I agree that both method points to that code. However, ICollection<T>
has inherited its GetEnumerator
method from IEnumerable<T>
. If you take a look at the source code for that interface, you can see that there is a method of type IEnumerator<T>
. So basically, what happens is that, for iEnum
, you are boxing the struct(which is a value type) to a reference type, where as, for listEnum
, the value is a struct, since you are calling List<T>.GetEnumerator()
directly. Below is the interface declaration of IEnumerable<T>
public interface IEnumerable<T> : IEnumerable
{
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
/// </returns>
/// <filterpriority>1</filterpriority>
IEnumerator<T> GetEnumerator();
}
You might also find this post[^] useful.
[/Edit]
这篇关于传递给方法时,List.Enumerator不更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!