枚举器和函数范围

vto*_*ola 2 c# ienumerable ienumerator

为什么a Enumerator不跟踪同一功能中的项目,如果MoveNext 操作发生在其他功能中则不然?

例:

    public static void Test()
    {
        var array = new List<Int32>(new Int32[] { 1, 2, 3, 4, 5 });
        var e = array.GetEnumerator();
        e.MoveNext();
        e.MoveNext();
        Console.WriteLine(e.Current); // 2
        Incremenet(e);
        Console.WriteLine(e.Current); //2
    }

    static void Incremenet(IEnumerator<Int32> e)
    {
        Console.WriteLine("Inside " + e.Current); //2
        e.MoveNext();
        Console.WriteLine("Inside " + e.Current); // 3
        e.MoveNext();
        Console.WriteLine("Inside " + e.Current); //4
    }
Run Code Online (Sandbox Code Playgroud)

我期望在最后一个CW中获得5分,但是我得到2分,就像它从未增加过一样.函数返回时为什么忘记函数MoveNext内部Increment

干杯.

Tim*_* S. 6

List<T>的枚举器类型List<T>.Enumerator不是a class,而是a struct.由于GetEnumerator暴露了返回类型List<T>.Enumerator,当你使用时var,e类型是List<T>.Enumerator,所以当你传递它时Incremenet,它会被自动装箱成一个IEnumerator<Int32>对象.这是你所看到的奇怪行为的原因.

如果键入e作为IEnumerator<Int32>,拳击,只要你得到的对象发生,所以这种奇怪的行为不会发生:它的工作原理,你是否在运行其他代码相同TestIncrement(我固定在该方法的拼写,顺便说一句,它不是"Incremenet").

public static void Test()
{
    var array = new List<Int32> { 1, 2, 3, 4, 5 };
    IEnumerator<Int32> e = array.GetEnumerator(); // boxed here
    e.MoveNext();
    e.MoveNext();
    Console.WriteLine(e.Current); // 2
    Increment(e);
    Console.WriteLine(e.Current); // now it's 4
}

static void Increment(IEnumerator<Int32> e)
{
    Console.WriteLine("Inside " + e.Current); // 2
    e.MoveNext();
    Console.WriteLine("Inside " + e.Current); // 3
    e.MoveNext();
    Console.WriteLine("Inside " + e.Current); // 4
}
Run Code Online (Sandbox Code Playgroud)

它是暴露的类型,而不是IEnumerator<T>出于性能原因.在这种情况下,它foreach 足够聪明,可以调用MoveNext并且Current不需要装箱或虚拟调度,并且可以毫无问题地处理值类型语义.它确实引起了混乱,正如你所看到的那样,当你不小心处理它的方式时,因为可变的structs是邪恶的.