枚举器行为变化基于我们如何引用它? [英] Enumerator behavior changes based on how we reference it?

查看:92
本文介绍了枚举器行为变化基于我们如何引用它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在类中包装对列表枚举器的引用似乎会改变其行为.带有匿名类的示例:

Wrapping a reference to the list's enumerator inside a class seems to change its behavior. Example with an anonymous class:

public static void Main()
{
    var list = new List<int>() { 1, 2, 3 };
    var an = new { E = list.GetEnumerator() };
    while (an.E.MoveNext())
    {
        Debug.Write(an.E.Current);
    }
}

我希望它打印"123",但它只打印零,并且永不终止.带有具体类的相同示例:

I would expect this to print "123", but it only prints zero and never terminates. The same example with a concrete class:

public static void Main()
{
    var list = new List<int>() { 1, 2, 3 };
    var an = new Foo()
    {
        E = list.GetEnumerator()
    };

    while (an.E.MoveNext())
    {
        Debug.Write(an.E.Current);
    }
}

public class Foo
{
    public List<int>.Enumerator E { get; set; }
}

这是怎么回事?

推荐答案

我测试了它,对我来说,它也不适用于您的具体课程.

I tested it and for me it does not work with your concrete class either.

原因是List<T>.Enumerator可变 struct,而an.E属性.

编译器会为每个自动属性生成一个后备字段,如下所示:

The compiler generates a backing field for each auto-property like this:

public class Foo
{
    private List<int>.Enumerator _E;
    public List<int>.Enumerator get_E() { return E; }
    public void set_E(List<int>.Enumerator value) { E = value; }
}

struct是一种值类型,因此,每次访问an.E时,都会得到该值的副本.

A struct is a value-type, so every-time you access an.E you get a copy of that value.

当您调用MoveNext()Current时,您在该副本的上调用它,并且此副本已被突变.

When you call MoveNext() or Current, you call it on that copy and this copy is mutated.

下次访问an.E呼叫MoveNext()Current时,您会得到尚未迭代的枚举器的新副本.

The next time you access an.E to call MoveNext() or Current you get a fresh copy of the not-yet-iterated enumerator.

an.E.Current0而不是1,因为-再次-您获得了尚未调用MoveNext()的新鲜枚举器.

And an.E.Current is 0 instead of 1 because - again - you get a fresh enumerator that MoveNext() was not yet called upon.

如果要存储列表的枚举数的引用,则可以使用类型为IEnumerator<int>的属性声明类Foo:

If you want to store a reference of the list's enumerator you could declare your class Foo with a property of type IEnumerator<int>:

public class Foo
{
    public IEnumerator<int> E { get; set; }
}

如果立即分配E = list.GetEnumerator();,则枚举器将被装箱并存储引用而不是 value .

If you assign E = list.GetEnumerator(); now, the enumerator gets boxed and a reference instead of a value is stored.

这篇关于枚举器行为变化基于我们如何引用它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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