为什么我的IEnumerable UserControl在用foreach枚举后被丢弃

本文关键字:枚举 foreach 我的 IEnumerable UserControl 在用 为什么 | 更新日期: 2023-09-27 17:59:57

我有一个带有内部列表的用户控件,我通过实现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());
    }
}

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

为什么我的IEnumerable UserControl在用foreach枚举后被丢弃

IEnumerator实现的接口之一是IDisposable。一旦处理完项目,foreach循环将在循环源上调用Dispose

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

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

例如

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

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

枚举器在foreach之后自动释放。

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

这是原因:

public IEnumerator GetEnumerator()
{
    return this;
}

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

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

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