C# Iterator and Field Keyword

Posted by lucianoes on Tue, 30 Jul 2019 06:42:33 +0200

Iterator pattern is one of design patterns, because of its universality, many languages have built-in native support.

In. NET, the iterator pattern is passed through IEnumerator,IEnumerable Two interfaces (non-generic and generic versions) are encapsulated

An important aspect of the iterator pattern is that instead of returning all data at once, only one element is returned per call.

 

The relationships among Array, IEnumerable and IEnumerator are as follows:

foreach traversal

(1) Array and collection container classes are derived from the IEnumerable interface class (which contains an IEnumerator GetEnumerator() interface function). Array and collection container classes implement this function, which allows foreach to traverse it.

Note: You don't need to derive from IEnumerable, as long as the class implements the IEnumerator GetEnumerator() function, you can use foreach to traverse the elements in that class.

(2) IEnumerator defines the Current attribute to return the element where the cursor is located, MoveNext moves to the next element (true if there are elements, false if at the end), and Reset resets the cursor to the first position.

int[] IntArray = new int[] { 1, 2, 3 };

foreach (int n in IntArray)
{
    Console.WriteLine(n);
}

// Above foreach Equivalent to the following code implementation
IEnumerator e = IntArray.GetEnumerator();
try
{
    while (e.MoveNext())
    {
        Console.WriteLine((int)e.Current);
    }
}
finally
{
    var disposable = e as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}

 

In C 1.0, creating an IEnumerator enumerator requires a lot of code. C#2.0 adds the yield statement to allow the compiler to automatically create the IEnumerator enumerator.

The yield return statement returns an element of the collection and moves to the next element. yield break stops iteration.

 

Non-generic version IEnumerator

class EnumeratorTest
{
    public IEnumerator GetEnumerator()
    {
        yield return 100;
        yield return "Good";
    }
}

EnumeratorTest eTest = new EnumeratorTest();
foreach (object o in eTest)
{
    Console.WriteLine(o);
}

The code generated after compilation is as follows:

class EnumeratorTest
{
    public IEnumerator GetEnumerator()
    {
        return new GenerateEnumerator(0);
    }

    private sealed class GenerateEnumerator : IEnumerator<object>, IEnumerator, IDisposable
    {
        // Fields
        private int  state;
        private object current;

        // Methods
        public GenerateEnumerator(int state)
        {
            this.state = state;
        }

        bool IEnumerator.MoveNext()
        {
            switch (this.state)
            {
                case 0:
                    this.state = -1;
                    this.current = 100;
                    this.state = 1;
                    return true;

                case 1:
                    this.state = -1;
                    this.current = "Good";
                    this.state = 2;
                    return true;

                case 2:
                    this.state = -1;
                    break;
            }
            return false;
        }

        void IEnumerator.Reset()
        {
            throw new NotSupportedException();
        }

        void IDisposable.Dispose()
        {
        }

        // Properties
        object IEnumerator<object>.Current
        {
            get
            {
                return this.current;
            }
        }
        object IEnumerator.Current
        {
            get
            {
                return this.current;
            }
        }
    }
}

EnumeratorTest eTest = new EnumeratorTest();
IEnumerator e = eTest.GetEnumerator();
try
{
    while (e.MoveNext())
    {
        Console.WriteLine(e.Current);
    }
}
finally
{
    var disposable = e as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}

Generic version IEnumerator<T>

class EnumeratorTest2
{
    private bool m_bBreak;

    public EnumeratorTest2(bool bBreak)
    {
        m_bBreak = bBreak;
    }

    public IEnumerator<string> GetEnumerator()
    {
        yield return "Hello";
        if (m_bBreak)
        {
            yield break;
        }
        yield return "World";
    }
}

EnumeratorTest2 eTest2 = new EnumeratorTest2(true);
IEnumerator<string> e2 = eTest2.GetEnumerator();
while (e2.MoveNext())
{
    Console.WriteLine(e2.Current);
}

The code generated after compilation is as follows:

class EnumeratorTest2
{
    private bool m_bBreak;

    public EnumeratorTest2(bool bBreak)
    {
        m_bBreak = bBreak;
    }

    public IEnumerator<string> GetEnumerator()
    {
        GenerateEnumerator2 e2 = new GenerateEnumerator2(0);
        e2.eTest2 = this;
        return e2;
    }

    private sealed class GenerateEnumerator2 : IEnumerator<string>, IEnumerator, IDisposable
    {
        // Fields
        private int state;
        private string current;

        public EnumeratorTest2 eTest2;

        // Methods
        public GenerateEnumerator2(int state)
        {
            this.state = state;
        }

        bool IEnumerator.MoveNext()
        {
            switch (this.state)
            {
                case 0:
                    this.state = -1;
                    this.current = "Hello";
                    this.state = 1;
                    return true;

                case 1:
                    this.state = -1;
                    if (eTest2.m_bBreak)
                    {
                        break;
                    }
                    this.current = "World";
                    this.state = 2;
                    return true;

                case 2:
                    this.state = -1;
                    break;
            }
            return false;
        }

        void IEnumerator.Reset()
        {
            throw new NotSupportedException();
        }

        void IDisposable.Dispose()
        {
        }

        // Properties
        string IEnumerator<string>.Current
        {
            get
            {
                return this.current;
            }
        }
        object IEnumerator.Current
        {
            get
            {
                return this.current;
            }
        }
    }
}

EnumeratorTest2 eTest2 = new EnumeratorTest2(true);
IEnumerator<string> e2 = eTest2.GetEnumerator();
while (e2.MoveNext())
{
    Console.WriteLine(e2.Current);
}

Non-generic version IEnumerable

class EnumeratorTest3
{
    public IEnumerable Test1()
    {
        yield return 100;
        yield return 200;
    }
}

EnumeratorTest3 eTest3 = new EnumeratorTest3();
foreach (object o in eTest3.Test1())
{
    Console.WriteLine(o);
}

The code generated after compilation is as follows:

class EnumeratorTest3
{
    public IEnumerable Test1()
    {
        return new GenerateEnumerable3(0);
    }

    private sealed class GenerateEnumerable3 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
    {
        // Fields
        private int state;
        private int current;

        // Methods
        public GenerateEnumerable3(int state)
        {
            this.state = state;
        }

        bool IEnumerator.MoveNext()
        {
            switch (this.state)
            {
                case 0:
                    this.state = -1;
                    this.current = 100;
                    this.state = 1;
                    return true;

                case 1:
                    this.state = -1;
                    this.current = 200;
                    this.state = 2;
                    return true;

                case 2:
                    this.state = -1;
                    break;
            }
            return false;
        }

        IEnumerator<object> IEnumerable<object>.GetEnumerator()
        {
            return this;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this;
        }

        void IEnumerator.Reset()
        {
            throw new NotSupportedException();
        }

        void IDisposable.Dispose()
        {
        }

        // Properties            
        object IEnumerator<object>.Current
        {
            get
            {
                return this.current;
            }
        }
        object IEnumerator.Current
        {
            get
            {
                return this.current;
            }
        }
    }
}

EnumeratorTest3 eTest3 = new EnumeratorTest3();
IEnumerator e3 = eTest3.Test1().GetEnumerator();
while (e3.MoveNext())
{
    Console.WriteLine(e3.Current);
}

Generic version IEnumerable < T >

class EnumeratorTest4
{
    private bool m_bBreak;

    public EnumeratorTest4(bool bBreak)
    {
        m_bBreak = bBreak;
    }

    public IEnumerable<float> Test1()
    {
        yield return 1.0f;
        if (m_bBreak)
        {
            yield break;
        }
        yield return 3.0f;
    }
}

EnumeratorTest4 eTest4 = new EnumeratorTest4(true);
foreach (object o in eTest4.Test1())
{
    Console.WriteLine(o);
}

The code generated after compilation is as follows:

class EnumeratorTest4
{
    private bool m_bBreak;

    public EnumeratorTest4(bool bBreak)
    {
        m_bBreak = bBreak;
    }

    public IEnumerable<float> Test1()
    {
        GenerateEnumerable4 e4 = new GenerateEnumerable4(0);
        e4.eTest4 = this;
        return e4;
    }

    private sealed class GenerateEnumerable4 : IEnumerable<float>, IEnumerable, IEnumerator<float>, IEnumerator, IDisposable
    {
        // Fields
        private int state;
        private float current;

        public EnumeratorTest4 eTest4;

        // Methods
        public GenerateEnumerable4(int state)
        {
            this.state = state;
        }

        bool IEnumerator.MoveNext()
        {
            switch (this.state)
            {
                case 0:
                    this.state = -1;
                    this.current = 1.0f;
                    this.state = 1;
                    return true;

                case 1:
                    this.state = -1;
                    if (this.eTest4.m_bBreak)
                    {
                        break;
                    }
                    this.current = 3.0f;
                    this.state = 2;
                    return true;

                case 2:
                    this.state = -1;
                    break;
            }
            return false;
        }

        IEnumerator<float> IEnumerable<float>.GetEnumerator()
        {
            return this;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this;
        }

        void IEnumerator.Reset()
        {
            throw new NotSupportedException();
        }

        void IDisposable.Dispose()
        {
        }

        // Properties            
        float IEnumerator<float>.Current
        {
            get
            {
                return this.current;
            }
        }
        object IEnumerator.Current
        {
            get
            {
                return this.current;
            }
        }
    }
}

EnumeratorTest4 eTest4 = new EnumeratorTest4(true);
IEnumerator<float> e4 = eTest4.Test1().GetEnumerator();
while (e4.MoveNext())
{
    Console.WriteLine(e4.Current);
}

Topics: PHP Attribute