可枚举对象与枚举器

1,最先学会的是,继承了IEnumerable接口的类都可以使用foreach遍历,但一直没有多想。

2,IEnumerable和IEnumerable<out T>的定义:
     public  interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }

     public  interface IEnumerable< out T> : IEnumerable
    {
        IEnumerator<T> GetEnumerator();
    }

3,IEnumerator和IEnumerator<out T>的定义:
     public  interface IEnumerator
    {
         object Current {  get; }
         bool MoveNext();
         void Reset();
    }

     public  interface IEnumerator< out T> : IDisposable, IEnumerator
    {
        T Current {  get; }
    }

4,可以这么理解两个接口:可枚举对象返回一个枚举器用于枚举其内部状态。

5,每一次foreach之后,都会重新调用GetEnumerator,foreach语句并不会调用Enumerator的Reset方法;
对于泛型版本的GetEnumerator<T>,foreach同样不会调用Reset方法,但会调用Dispose。
以下是测试代码的输出:
[08.177] StringEnumerator
[08.191] StringMoveNext
[08.191] StringCurrent
Hello
[08.191] StringMoveNext
[08.191] StringCurrent
World
[08.191] StringMoveNext
[08.191] StringCurrent
!
[08.192] StringMoveNext
[08.192] StringEnumerator
[08.192] StringMoveNext
[08.192] StringCurrent
Hello
[08.192] StringMoveNext
[08.192] StringCurrent
World
[08.193] StringMoveNext
[08.193] StringCurrent
!
[08.193] StringMoveNext
[08.195] NumberEnumerator
[08.196] NumberMoveNext
[08.196] NumberCurrent<T>
1
[08.198] NumberMoveNext
[08.199] NumberCurrent<T>
2
[08.199] NumberMoveNext
[08.201] NumberDispose
[08.201] NumberEnumerator
[08.201] NumberMoveNext
[08.202] NumberCurrent<T>
1
[08.202] NumberMoveNext
[08.203] NumberCurrent<T>
2
[08.203] NumberMoveNext
[08.203] NumberDispose

using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleTest
{
     public  class Program
    {
         static  void Main( string[] args)
        {
            StringEnumerable se =  new StringEnumerable(); 
             foreach ( string s  in se)
            {
                Console.WriteLine(s);
            }
             foreach ( string s  in se)
            {
                Console.WriteLine(s);
            }
            Console.WriteLine();

            NumberEnumerable< double> ne =  new NumberEnumerable< double>( new  double[] { 1.0, 2.0 });
             foreach ( double d  in ne)
            {
                Console.WriteLine(d);
            }
             foreach ( double d  in ne)
            {
                Console.WriteLine(d);
            }
            Console.ReadKey();
        }
    }

     class StringEnumerable : IEnumerable
    {
         private  string[] strs =  new  string[] { "Hello", "World", "!" };

         public IEnumerator GetEnumerator()
        {
             return  new StringEnumerator(strs);
        }
    }

     class StringEnumerator : IEnumerator
    {
         private  string[] strs;
         private  int index;
         private  object current;

         public StringEnumerator( string[] strs)
        {
            Console.WriteLine("[{0}] StringEnumerator", DateTime.Now.ToString("ss.fff"));
             this.strs = strs;
            index = -1;
        }

         public  object Current
        {
             get
            {
                Console.WriteLine("[{0}] StringCurrent", DateTime.Now.ToString("ss.fff"));
                 return current;
            }
        }

         public  bool MoveNext()
        {
            Console.WriteLine("[{0}] StringMoveNext", DateTime.Now.ToString("ss.fff"));
             while (++index < strs.Length)
            {
                current = strs[index];
                 return  true;
            }
             return  false;
        }

         public  void Reset()
        {
            Console.WriteLine("[{0}] StringReset", DateTime.Now.ToString("ss.fff"));
            index = -1;
        }
    }

     class NumberEnumerable<T> : IEnumerable<T>
    {
         private T[] ts;

         public NumberEnumerable(T[] ts)
        {
             this.ts = ts;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
             return  new NumberEnumerator<T>(ts);
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
             return  new NumberEnumerator<T>(ts);
        }
    }

     class NumberEnumerator<T> : IEnumerator<T>
    {
         private T[] strs;
         private  int index;
         private T current;

         public NumberEnumerator(T[] strs)
        {
            Console.WriteLine("[{0}] NumberEnumerator", DateTime.Now.ToString("ss.fff"));
             this.strs = strs;
            index = -1;
        }

         object IEnumerator.Current
        {
             get
            {
                Console.WriteLine("[{0}] NumberCurrent", DateTime.Now.ToString("ss.fff"));
                 return current;
            }
        }

        T IEnumerator<T>.Current
        {
             get
            {
                Console.WriteLine("[{0}] NumberCurrent<T>", DateTime.Now.ToString("ss.fff"));
                 return current;
            }
        }

         public  bool MoveNext()
        {
            Console.WriteLine("[{0}] NumberMoveNext", DateTime.Now.ToString("ss.fff"));
             while (++index < strs.Length)
            {
                current = strs[index];
                 return  true;
            }
             return  false;
        }

         public  void Reset()
        {
            Console.WriteLine("[{0}] NumberReset", DateTime.Now.ToString("ss.fff"));
            index = -1;
        }

         public  void Dispose()
        {
            Console.WriteLine("[{0}] NumberDispose", DateTime.Now.ToString("ss.fff"));
            index = -1;
        }
    }
}

6
,foreach默认可枚举对象的GetEnumerator方法,其他需要进行枚举的方法需要返回IEnumerable或者IEnumerable<T>,以供foreach调用其GetEnumerator方法。

7,yield语句只能使用在返回IEnumerable或者IEnumerator接口的方法中。
yield语句会被编译为实现了IEnumerator<T>的内部枚举器。
以下是代码使用.NET Reflector 7.0反编译出来的结果:
using System;
using System.Collections;
using System.Collections.Generic;

namespace YieldTest
{
     class Program
    {
         static  void Main( string[] args)
        {
            YieldString ys =  new YieldString();
             foreach ( string s  in ys)
            {
                Console.WriteLine(s);
            }
             foreach ( string s  in ys.Next())
            {
                Console.WriteLine(s);
            }
            Console.ReadKey();
        }
    }

     class YieldString
    {
         private  string[] strs =  new  string[] { "Hello", "World", "!" };

         public IEnumerator GetEnumerator()
        {
             foreach ( string s  in strs)
            {
                yield  return s;
            }
        }

         public IEnumerable Next()
        {
             foreach ( string s  in strs)
            {
                yield  return s;
            }
        }
    }
}

internal  class YieldString
{
     //  Fields
     private  string[] strs =  new  string[] { "Hello", "World", "!" };

     //  Methods
     public IEnumerator GetEnumerator()
    {
         foreach ( string iteratorVariable0  in  this.strs)
        {
            yield  return iteratorVariable0;
        }
    }

     public IEnumerable Next()
    {
         foreach ( string iteratorVariable0  in  this.strs)
        {
            yield  return iteratorVariable0;
        }
    }

     //  Nested Types
    [CompilerGenerated]
     private  sealed  class <GetEnumerator>d__0 : IEnumerator< object>, IEnumerator, IDisposable
    {
         //  Fields
         private  int <>1__state;
         private  object <>2__current;
         public YieldString <>4__this;
         public  string[] <>7__wrap3;
         public  int <>7__wrap4;
         public  string <s>5__1;

         //  Methods
        [DebuggerHidden]
         public <GetEnumerator>d__0( int <>1__state)
        {
             this.<>1__state = <>1__state;
        }

         private  void <>m__Finally2()
        {
             this.<>1__state = -1;
        }

         private  bool MoveNext()
        {
             try
            {
                 switch ( this.<>1__state)
                {
                     case 0:
                         this.<>1__state = -1;
                         this.<>1__state = 1;
                         this.<>7__wrap3 =  this.<>4__this.strs;
                         this.<>7__wrap4 = 0;
                         while ( this.<>7__wrap4 <  this.<>7__wrap3.Length)
                        {
                             this.<s>5__1 =  this.<>7__wrap3[ this.<>7__wrap4];
                             this.<>2__current =  this.<s>5__1;
                             this.<>1__state = 2;
                             return  true;
                        Label_0079:
                             this.<>1__state = 1;
                             this.<>7__wrap4++;
                        }
                         this.<>m__Finally2();
                         break;

                     case 2:
                         goto Label_0079;
                }
                 return  false;
            }
            fault
            {
                 this.System.IDisposable.Dispose();
            }
        }

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

         void IDisposable.Dispose()
        {
             switch ( this.<>1__state)
            {
                 case 1:
                 case 2:
                     this.<>m__Finally2();
                     break;
            }
        }

         //  Properties
         object IEnumerator< object>.Current
        {
            [DebuggerHidden]
             get
            {
                 return  this.<>2__current;
            }
        }

         object IEnumerator.Current
        {
            [DebuggerHidden]
             get
            {
                 return  this.<>2__current;
            }
        }
    }

    [CompilerGenerated]
     private  sealed  class <Next>d__6 : IEnumerable< object>, IEnumerable, IEnumerator< object>, IEnumerator, IDisposable
    {
         //  Fields
         private  int <>1__state;
         private  object <>2__current;
         public YieldString <>4__this;
         public  string[] <>7__wrap9;
         public  int <>7__wrapa;
         private  int <>l__initialThreadId;
         public  string <s>5__7;

         //  Methods
        [DebuggerHidden]
         public <Next>d__6( int <>1__state)
        {
             this.<>1__state = <>1__state;
             this.<>l__initialThreadId = Thread.CurrentThread.ManagedThreadId;
        }

         private  void <>m__Finally8()
        {
             this.<>1__state = -1;
        }

         private  bool MoveNext()
        {
             try
            {
                 switch ( this.<>1__state)
                {
                     case 0:
                         this.<>1__state = -1;
                         this.<>1__state = 1;
                         this.<>7__wrap9 =  this.<>4__this.strs;
                         this.<>7__wrapa = 0;
                         while ( this.<>7__wrapa <  this.<>7__wrap9.Length)
                        {
                             this.<s>5__7 =  this.<>7__wrap9[ this.<>7__wrapa];
                             this.<>2__current =  this.<s>5__7;
                             this.<>1__state = 2;
                             return  true;
                        Label_0079:
                             this.<>1__state = 1;
                             this.<>7__wrapa++;
                        }
                         this.<>m__Finally8();
                         break;

                     case 2:
                         goto Label_0079;
                }
                 return  false;
            }
            fault
            {
                 this.System.IDisposable.Dispose();
            }
        }

        [DebuggerHidden]
        IEnumerator< object> IEnumerable< object>.GetEnumerator()
        {
             if ((Thread.CurrentThread.ManagedThreadId ==  this.<>l__initialThreadId) && ( this.<>1__state == -2))
            {
                 this.<>1__state = 0;
                 return  this;
            }
             return  new YieldString.<Next>d__6(0) { <>4__this =  this.<>4__this };
        }

        [DebuggerHidden]
        IEnumerator IEnumerable.GetEnumerator()
        {
             return  this.System.Collections.Generic.IEnumerable<System.Object>.GetEnumerator();
        }

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

         void IDisposable.Dispose()
        {
             switch ( this.<>1__state)
            {
                 case 1:
                 case 2:
                     this.<>m__Finally8();
                     break;
            }
        }

         //  Properties
         object IEnumerator< object>.Current
        {
            [DebuggerHidden]
             get
            {
                 return  this.<>2__current;
            }
        }

         object IEnumerator.Current
        {
            [DebuggerHidden]
             get
            {
                 return  this.<>2__current;
            }
        }
    }
}

你可能感兴趣的:(可枚举对象与枚举器)