IEnumerable和IEnumerator接口

Posted 积少成多

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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接口的主要内容,如果未能解决你的问题,请参考以下文章

转载 IEnumerable和IEnumerator 详解

C# IEnumerator IEnumerable接口

IEnumerable和IEnumerator详解

IEnumerator和IEnumerable

IEnumerable和IEnumerator的区别

IEnumerator和IEnumerable详解