Why is my IEnumerable UserControl removed after I enumerate it using foreach?

I have a usercontrol with an internal list that I published publicly using IEnumerable. When I use foreach to list it, the user control is removed. Why is this happening?

Playback Example:

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()); } } 

Run it in the debugger and click the black square.

+4
source share
3 answers

One of the interfaces implemented in IEnumerator is IDisposable . The foreach will call Dispose on the loop source after the elements have been processed.

The best solution would be to turn your UserControl into 2 parts

  • UserControl minus enumerated interfaces
  • Property / method providing the collection it contains

for instance

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

Since your control is its own enumerator :-)

The enumerator is automatically deleted after foreach .

I would suggest making an enumerator in a separate class. Or, alternatively, just use the standard collection as a member, and not create the control as IEnumerable .

+4
source

This is the reason:

 public IEnumerator GetEnumerator() { return this; } 

One of the IEnumerator IDisposable , the foreach loop at the end of the call calls the Dispose method.

You must provide a new IEnumerator each time the GetEnumerator method is called, and avoid using both interfaces in the same implementation. This is done by LINQ, but this is a specific situation.

Instead of IEnumerator in the VanishingControl class, you should have a subclass that implements IEnumerator , and a new instance of this class is returned in GetEnumeratiorn.

+2
source

All Articles