传递给方法时,List.Enumerator不更新 [英] List.Enumerator not updated when passed to method

查看:89
本文介绍了传递给方法时,List.Enumerator不更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个方法,该方法以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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆