Foreach Statement Calls Dispose() on IEnumerator

Again, something that might seems natural because you generally don’t see it or even think about it, but interesting to know.

If the IEnumerator/IEnumerator<T> returned by the GetEnumerator() function of a collection that is foreach-ed implements IDisposable, Dispose() will be called on it when the foreach is over.

Here is a sample code that does just that:

class Program
    {
        static void Main(string[] args)
        {
            foreach (var item in new SomeEnumerable())
            {
                Console.WriteLine(item);
            }

            Console.ReadLine();
        }

        class SomeEnumerable : IEnumerable<String>
        {
            #region IEnumerable<string> Members

            public IEnumerator<String> GetEnumerator()
            {
                return new CustomEnumerator(new List<String>() { "One", "Two" }.GetEnumerator());
            }

            #endregion

            #region IEnumerable Members

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }

            #endregion

            class CustomEnumerator : IEnumerator<String>
            {
                IEnumerator<String> enumerator;

                public CustomEnumerator(IEnumerator<String> enumerator)
                {
                    this.enumerator = enumerator;
                }

                #region IEnumerator<string> Members

                public string Current
                {
                    get { return this.enumerator.Current; }
                }

                #endregion

                #region IDisposable Members

                public void Dispose()
                {
                    Console.WriteLine("SomeEnumerable Enumerator Disposed!");

                    this.enumerator.Dispose();
                }

                #endregion

                #region IEnumerator Members

                object System.Collections.IEnumerator.Current
                {
                    get { return this.enumerator.Current; }
                }

                public bool MoveNext()
                {
                    return this.enumerator.MoveNext();
                }

                public void Reset()
                {
                    this.enumerator.Reset();
                }

                #endregion
            }
        }
    }

You can look at the two possible code expansions for the foreach statement on the MSDN page.

Comments

Comments are closed.