首页 > 代码库 > IEnumerable和IEnumerator接口

IEnumerable和IEnumerator接口

我们先思考几个问题:
1.为什么在foreach中不能修改item的值?(IEnumerator的Current为只读)
2.要实现foreach需要满足什么条件?(实现IEnumerator接口来实现的)
3.为什么Linq to Object中要返回IEnumerable?(因为IEnumerable是延迟加载的,每次访问的时候才取值。也就是我们在Lambda里面写的where、select并没有循环遍历(只是在组装条件),只有在ToList或foreache的时候才真正去集合取值了。这样大大提高了性能。)

.net中迭代器是通过IEnumerable和IEnumerator接口来实现的,今天我们也来依葫芦画瓢。

using System;using System.Collections;namespace RedisTest{    class Program    {        static void Main(string[] args)        {            string[] str = { "1111", "2222", "3333", "4444", "5555" };            var aaa = new MyIEnumerable(str);            var bbb = aaa.GetEnumerator();            while (bbb.MoveNext())            {                Console.WriteLine(bbb.Current);            }            Console.WriteLine("---------------------------------------------------------");            foreach (var item in aaa)            {                Console.WriteLine(item);            }            Console.Read();            /*            1111            2222            3333            4444            5555            ---------------------------------------------------------            1111            2222            3333            4444            5555            */        }    }    public class MyIEnumerable : IEnumerable    {        private string[] strList;        public MyIEnumerable(string[] _strList)        {            strList = _strList;        }        public IEnumerator GetEnumerator()        {            return new MyIEnumerator(strList);        }    }    public class MyIEnumerator : IEnumerator    {        private string[] strList;        private int position;        public MyIEnumerator(string[] _strList)        {            strList = _strList;            position = -1;        }        public object Current        {            get            {                return strList[position];            }        }        public bool MoveNext()        {            position++;            if (position < strList.Length)                return true;            return false;        }        public void Reset()        {            position = -1;        }    }}

yield的使用

using System;using System.Collections;namespace RedisTest{    class Program    {        static void Main(string[] args)        {            string[] str = { "1111", "2222", "3333", "4444", "5555" };            var aaa = new MyIEnumerable(str);            var bbb = aaa.GetEnumerator();            while (bbb.MoveNext())            {                Console.WriteLine(bbb.Current);            }            Console.WriteLine("---------------------------------------------------------");            foreach (var item in aaa)            {                Console.WriteLine(item);            }            Console.Read();            /*            1111            2222            3333            4444            5555            ---------------------------------------------------------            1111            2222            3333            4444            5555            */               }    }    public class MyIEnumerable    {        private string[] strList;        public MyIEnumerable(string[] _strList)        {            strList = _strList;        }        public IEnumerator GetEnumerator()        {            for (int i = 0; i < strList.Length; i++)            {                yield return strList[i];            }        }    }}

我们调用GetEnumerator的时候,看似里面for循环了一次,其实这个时候没有做任何操作。只有调用MoveNext的时候才会对应调用for循环:

using System;using System.Collections;using System.Collections.Generic;using System.Linq;namespace RedisTest{    class Program    {        static void Main(string[] args)        {            string[] str = { "1111", "2222", "3333", "4444", "5555" };            var aaa = new MyIEnumerable(str);            var bbb = aaa.MyWhere(x => x != "1111");            var ccc = bbb.ToList();            //现在看到了吧。执行到MyWhere的时候什么动作都没有(返回的就是IEnumerable),只有执行到ToList的时候才代码才真正的去遍历筛选。            //这里的MyWhere其实可以用扩展方法来实现,提升逼格。(Linq的那些查询操作符就是以扩展的形式实现的)            Console.Read();        }    }    public class MyIEnumerable    {        private string[] strList;        public MyIEnumerable(string[] _strList)        {            strList = _strList;        }        public IEnumerator GetEnumerator()        {            for (int i = 0; i < strList.Length; i++)            {                yield return strList[i];            }        }        public IEnumerable<string> MyWhere(Func<string, bool> func)        {            foreach (string item in this)            {                if (func(item))                {                    yield return item;                }            }        }    }}

 

IEnumerable和IEnumerator接口