为什么我的IEnumerable UserControl在使用foreach枚举之后处理掉了?

时间:2011-06-21 16:02:23

标签: c# .net user-controls ienumerable

我有一个带有内部列表的usercontrol,我通过实现IEnumerable公开地公开了它。当我使用foreach对其进行枚举时,用户控件将被释放。为什么会这样?

重现的例子:

using System;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;

public class VanishingControl : UserControl, IEnumerable, IEnumerator
{
    string[] strings = { "uno", "due", "tres" };
    int position = -1;

    public IEnumerator GetEnumerator()
    {
        return this;
    }

    public object Current
    {
        get { return strings[position]; }
    }

    public bool MoveNext()
    {
        position++;
        return position < strings.Length;
    }

    public void Reset()
    {
        position = 0;
    }

    protected override void Dispose(bool disposing)
    {
        Console.WriteLine("bye!");
        base.Dispose(disposing);
    }
}

public class Vanish : Form
{
    private VanishingControl vc = new VanishingControl();

    public Vanish()
    {
        vc.BackColor = Color.Black;
        vc.Click += vc_Click;
        Controls.Add(vc);
    }

    void vc_Click(object sender, EventArgs e)
    {
        foreach (string s in vc)
            Console.WriteLine(s);
    }

    [STAThread]
    static void Main()
    {
        Application.Run(new Vanish());
    }
}

在调试器中运行它,然后单击黑色方块。

3 个答案:

答案 0 :(得分:4)

因为你的控件是它自己的枚举器: - )

枚举器会在foreach之后自动处理。

我建议将枚举器放入一个单独的类中。或者,或者,只使用标准集合作为成员,而不是使控件本身为IEnumerable

答案 1 :(得分:4)

IEnumerator实施的其中一个界面是IDisposable。一旦处理完项目,foreach循环将在循环源上调用Dispose

更好的解决方案是将UserControl分为两部分

  1. UserControl减去可枚举的接口
  2. 公开其包含的集合的属性/方法
  3. 例如

    public class VanishingControl : UserControl
    {
      string[] strings = { "uno", "due", "tres" };
    
      public IEnumerable<string> GetItems() {
        foreach (var current in strings) {
          yield return current;
        }
      }
    }
    

答案 2 :(得分:2)

这是原因:

public IEnumerator GetEnumerator()
{
    return this;
}

IEnumerator接口之一是IDisposable,工作结束时的foreach循环调用Dispose方法。

每次调用GetEnumerator方法时都应该提供新的IEnumerator,并避免在一个实现中使用这两个接口。这是由LINQ完成的,但这是具体的情况。

而不是类IEnumerator中的VanishingControl,而是应该有一个实现IEnumerator的子类,而在GetEnumeratiorn中,将返回该类的新实例。