IEnumerable和IEnumerator

概述

IEnumerable和IEnumerator接口存在的意義:用來實現迭代的功能!編程

    public interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }

    public interface IEnumerator
    {
        object Current { get; }

        bool MoveNext();

        void Reset();
    }

迭代的原理

首先來講一下集合實現的原理:對於ArrayList、List<T>等集合,類中有一個私有的數組類型字段,向集合中添加數據時調用Add方法(將數據元素添加到私有數組字段中),而調用類的其餘方法時,其實就是對私有數組類型字段的操做。數組

 1 public class ArrayList : IList, ICollection, IEnumerable, ICloneable
 2 {
 3     //省略其餘代碼
 4     private object[] _items;
 5     
 6     public virtual int Add(object value)
 7     {
 8         if (this._size == this._items.Length)
 9         {
10             this.EnsureCapacity(this._size + 1);
11         }
12         this._items[this._size] = value;
13         this._version++;
14         return this._size++;
15     }
16 }
ArrayList
 1 public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
 2 {
 3     //省略其餘代碼
 4     private T[] _items;
 5     
 6     public void Add(T item)
 7     {
 8         if (this._size == this._items.Length)
 9         {
10             this.EnsureCapacity(this._size + 1);
11         }
12         this._items[this._size++] = item;
13         this._version++;
14     }
15 }
List

因此對於這些集合來講,本質上集合中的全部元素都是保存在一個私有數組類型的字段中,衆所周知,對於ArrayList或者List<T>均可以使用foreach進行迭代,查看集合中的元素。app

        static void Main(string[] args)
        {
            List<string> strs=new List<string>();
            strs.Add("DD");
            strs.Add("FF");
            strs.Add("VV");
            strs.Add("WW");
            foreach (String str in strs)
            {
                Console.WriteLine(str);
            }
            Console.ReadKey();
        }

上述這個foreach的迭代的過程是如何實現的呢?foreach爲何能夠逐個遍歷因此集合中的元素呢?下面咱們就用IL反彙編程序來查看上述代碼的foreach部分的IL!
ide

  IL_0039:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
  IL_003e:  stloc.2
  .try
  {
    IL_003f:  br.s       IL_0052
    IL_0041:  ldloca.s   CS$5$0000
    IL_0043:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current()
    IL_0048:  stloc.1
    IL_0049:  nop
    IL_004a:  ldloc.1
    IL_004b:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0050:  nop
    IL_0051:  nop
    IL_0052:  ldloca.s   CS$5$0000
    IL_0054:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext()
    IL_0059:  stloc.3
    IL_005a:  ldloc.3
    IL_005b:  brtrue.s   IL_0041
    IL_005d:  leave.s    IL_006e
  }  // end .try
  finally
  {
    IL_005f:  ldloca.s   CS$5$0000
    IL_0061:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
    IL_0067:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_006c:  nop
    IL_006d:  endfinally
  }

看不懂?不要緊啦,那麼咱們就來大體的猜測一下,咱們的foreach生成了這麼一大坨的IL中竟然有Enumerator什麼的,難道跟這個有關係嗎?恰巧據說IEnumerable和IEnumrator用來實現迭代,偏偏巧咱們的ArrayList、List<T>集合都是實現了IEnumerable接口。那麼咱們就來作的大膽的假設,foreach其實就是執行跟IEnumerable和IEnumrator接口相關的代碼,並對保存集合的私有數組字段的索引進行操做,從而來實現迭代的功能。學習

static void Main(string[] args)
{
	List<string> strs=new List<string>();
	strs.Add("DD");
	strs.Add("FF");
	strs.Add("VV");
	strs.Add("WW");
	IEnumerator<string> items = strs.GetEnumerator();
	while (items.MoveNext())
	{
		Console.WriteLine(items.Current);
	}
	Console.ReadKey();
}

這段代碼也一樣實現了對集合元素迭代的功能!在來看一下這個迭代生成的相關IL。測試

  IL_0038:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()
  IL_003d:  box        valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>
  IL_0042:  stloc.1
  IL_0043:  br.s       IL_0053
  IL_0045:  nop
  IL_0046:  ldloc.1
  IL_0047:  callvirt   instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current()
  IL_004c:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0051:  nop
  IL_0052:  nop
  IL_0053:  ldloc.1
  IL_0054:  callvirt   instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
  IL_0059:  stloc.2
  IL_005a:  ldloc.2
  IL_005b:  brtrue.s   IL_0045

嘿嘿,對比二者生成的IL,目測他們的執行過程當中調用的IL指令大致上是一致的(IL指令啥的暫時我也不是很瞭解),因此咱們的猜測應該是正確的,foreach在本質上其實就是經過ArrayList、List<T>中定義的GetEnumerator方法,以及後續的代碼實現的!下面就來看看List<T>中是如何定義的。this

public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
    private T[] _items;
    public List<T>.Enumerator GetEnumerator()
    {
        return new List<T>.Enumerator(this);
    }
    public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator
    {
        private List<T> list;
        private int index;
        private int version;
        private T current;
        
        public T Current
        {
            
            get
            {
                return this.current;
            }
        }
        
        object IEnumerator.Current
        {
            
            get
            {
                if (this.index == 0 || this.index == this.list._size + 1)
                {
                    ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen);
                }
                return this.Current;
            }
        }
        internal Enumerator(List<T> list)
        {
            this.list = list;
            this.index = 0;
            this.version = list._version;
            this.current = default(T);
        }
        
        public void Dispose()
        {
        }

        public bool MoveNext()
        {
            List<T> list = this.list;
            if (this.version == list._version && this.index < list._size)
            {
                this.current = list._items[this.index];
                this.index++;
                return true;
            }
            return this.MoveNextRare();
        }
        private bool MoveNextRare()
        {
            if (this.version != this.list._version)
            {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
            }
            this.index = this.list._size + 1;
            this.current = default(T);
            return false;
        }
        
        void IEnumerator.Reset()
        {
            if (this.version != this.list._version)
            {
                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
            }
            this.index = 0;
            this.current = default(T);
        }
    }
}    
        
List<T>

哇哦,原來迭代器是這樣的呀!!!!spa

自定義一個簡單的支持迭代的集合

下面咱們就來自定義一個支持迭代器的集合3d

public class UserDefinedCollection<T>:IEnumerable<T>
    {
        private List<T> list = new List<T>();

        public UserDefinedCollection(List<T> param)
        {
            list = param;
        }
        public IEnumerator<T> GetEnumerator()
        {
            return new UserDefinedEnum<T>(list);
        }

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

        private sealed class UserDefinedEnum<T>:IEnumerator<T>
        {
            private List<T> list = null;
            private int _CurrentIndex;
            private T _CurrentElement;

            public UserDefinedEnum(List<T> param)
            {
                this.list = param;
                this._CurrentIndex = 0;
                _CurrentElement = default(T);
                
            }

            public T Current
            {
                get 
                {
                    return _CurrentElement;
                }
            }

            object IEnumerator.Current
            {
                get { return Current; }
            }

            public bool MoveNext()
            {
                if (this._CurrentIndex < this.list.Count)
                {
                    this._CurrentElement = this.list[this._CurrentIndex++];
                    return true;
                }
                return false;
            }

            public void Reset()
            {
                this._CurrentElement = default(T);
                this._CurrentIndex = 0;
            }
            public void Dispose()
            {
                
            }
        }

    }

 測試自定義集合的迭代功能:code

            List<string> strs=new List<string>();
            strs.Add("DD");
            strs.Add("FF");
            strs.Add("VV");
            strs.Add("WW");
            UserDefinedCollection<String> user = new UserDefinedCollection<string>(strs);
            IEnumerator<string> iEnumerator = user.GetEnumerator();
            
            while (iEnumerator.MoveNext())
            {
                Console.WriteLine(iEnumerator.Current);
            }
            
            foreach (String str in user)
            {
                Console.WriteLine(str);
            }

 

擴展:由模型綁定中,綁定泛型類型時學習到泛型相關的知識!

//調用1
    ExtraGenericInterface(typeof(List<User>),typeof(IEnumerable<>))
    //調用2
    ExtraGenericInterface(typeof(IEnumerable<User>),typeof(IEnumerable<>))

    public Type ExtraGenericInterface(Type queryType, Type interfaceType)
        {
            //當前類型queryType是不是泛型
            bool b = queryType.IsGenericType;
            //返回能夠構造當前泛型類型的一個泛型類型,即:由IEnumerable<User>獲得 IEnumerable<>
            Type tt = queryType.GetGenericTypeDefinition();

            bool ttt = tt == interfaceType ? true : false;

            Func<Type, bool> predicate = t => t.IsGenericType && (t.GetGenericTypeDefinition() == interfaceType);
            //Func<Type, bool> predicate = delegate(Type queryType2){return false;};
            //若是當前類型是泛型,而且該發行是由interfaceType類型構造的。
            if (predicate(queryType))
            {
                return queryType;
            }
            else
            {
                //獲取當前類實現的全部類和接口
                Type[] types = queryType.GetInterfaces();
                //在數組中找,並返回知足 predicate 條件的第一個元素
                //也就是在全部父類或實現的接口中找到是泛型而且構造此泛型的類型是interfaceType類型的第一個元素
         //FirstOrDefault<Type>中Type是後面委託predicate的參數類型 
                Type tttt = types.FirstOrDefault<Type>(predicate);

                return queryType.GetInterfaces().FirstOrDefault<Type>(predicate);
            }
            
        }
相關文章
相關標籤/搜索