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;
                }
            }
        }
    }

}
时间: 2024-10-05 13:26:29

IEnumerable和IEnumerator接口的相关文章

迭代器学习之一:使用IEnumerable和IEnumerator接口

写博客是检验我学习的成果之一以及自我总结的一种方式,以后会经常利用这种方式进行技术交流和自我总结,其中认识不深难免会有错误,但是一直懂得不懂就问,不懂就学的道理! 1.首先看一个简单的列子 1 int[] myArray = { 1, 32, 43, 343 }; 2 //很少这样写的 3 IEnumerator myie = myArray.GetEnumerator(); //获取需要遍历的枚举数 4 myie.Reset(); //重置 5 while (myie.MoveNext())

IEnumerable和IEnumerator 详解

http://blog.csdn.net/byondocean/article/details/6871881 初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下面我们先看IEnumerable和IEnumerator两个接口的语法定义.其实IEnumerable接口是非常的简单,只包含一个抽象的方法GetEnumerator(),它返回一个可用于

C# IEnumerable和IEnumerator的区别,如何实现

IEnumerable接口和IEnumerator接口是.NET中非常重要的接口,二者有何区别? 1. 简单来说IEnumerable是一个声明式的接口,声明实现该接口的类就是"可迭代的enumerable",但并没用说明如何实现迭代器(iterator).其代码实现为: public interface IEnumerable         {                IEnumerator GetEnumerator();          }    2. 而IEnumer

IList,ICollection,IEnumerable,IEnumerator,IQueryable

1.首先看一个简单的例子 int[] myArray = { 1, 32, 43, 343 }; IEnumerator myie = myArray.GetEnumerator(); myie.Reset(); while (myie.MoveNext()) { int i = (int)myie.Current; Console.WriteLine("Value: {0}", i); } 相信很多人都不会像上面这样去遍历myArray这个数组,通常我们这样会这样做 foreach

转载 IEnumerable和IEnumerator 详解

初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下面我们先看IEnumerable和IEnumerator两个接口的语法定义.其实IEnumerable接口是非常的简单,只包含一个抽象的 方法GetEnumerator(),它返回一个可用于循环访问集合的IEnumerator对象.IEnumerator对象有什么呢?它是一个真正的 集合访问器,没有

&lt;转载&gt;C#IEnumerable和IEnumerator 详解

初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下面我们先看IEnumerable和IEnumerator两个接口的语法定义.其实IEnumerable接口是非常的简单,只包含一个抽象的方法GetEnumerator(),它返回一个可用于循环访问集合的IEnumerator对象.IEnumerator对象有什么呢?它是一个真正的集合访问器,没有它,

[转]那些年我还不懂:IList,ICollection,IEnumerable,IEnumerator,IQueryable

1.首先看一个简单的例子 int[] myArray = { 1, 32, 43, 343 }; IEnumerator myie = myArray.GetEnumerator(); myie.Reset(); while (myie.MoveNext()) { int i = (int)myie.Current; Console.WriteLine("Value: {0}", i); } 相信很多人都不会像上面这样去遍历myArray这个数组,通常我们这样会这样做 foreach

IEnumerable和IEnumerator详解

引言 IEnumerable是可枚举的所有非泛型集合的基接口, IEnumerable包含一个方法GetEnumerator(),该方法返回一个IEnumerator:IEnumerator提供通过Current属性以及MoveNext()和Reset()方法来循环访问集合的功能. IEnumerable 接口 公开枚举数,该枚举数支持在非泛型集合上进行简单迭代.接口源码如下: public interface IEnumerable { [DispId(-4), __DynamicallyIn

《转》IEnumerable、IEnumerator两个接口的认识

前言 IEnumerable.IEnumerator到现在为止对这两个接口还是不太理解,不理解但是自己总是想着试着要搞明白,毕竟自己用的少,所以在此先记录一下. 查看并使用两个接口 接下来我们先来看看两个接口的定义. 先来看一下IEnumerable接口,其实看过这个接口之后,发现它其实是非常的简单,只包含一个方法GetEnumerator(),它返回一个可用于循环访问集合的IEnumerator对象,如下面截图所示: 这里的IEnumerator对象,其实就是另外一个接口,这个接口对象有什么呢