[CSharp In Depth]迭代器

       最近好多事请,好多事情都反反复复,这样的结果就是给人很大的挫败感。从今以后,做什么事一定要有头有尾,坚持完成!
       除了集合类型可以使用Foreach,其他的内容也可以使用Foreach来遍历,使用Foreach保证了类型统一安全,代码简洁高效。
       要想使用Foreach的语法规则进行遍历,只需要实现IEnumberable<T>接口,而该接口的实现就是要实现IEnumerator<T>,在C#2中已经引入的yield return完美的解决了这个问题。
      

        IEnumerable<int> GetEnumerable()
        {
            for (int i = 0; i < 10; i++)
                yield return i;
        }

这是最简单的样子。

做一点有意思的工作,比如按行来编译文件呢?

  IEnumerable<string> GetEnumerable(string filename)
        {
           using(TextReader reader = File.OpenText(filename))
           {
               string line;
               while ((line = reader.ReadLine()) != null)
               {
                   yield return line;
               }
           }
        }
这样实现用一次没有什么问题,但是从设计的角度来看,reader的控制权和生命周期均被透明化了,而且只是支持一个txt文件,如果考虑一个网络的文本呢,进行改进:

考虑将reader对象作为形参传入,其实是引入了更大的问题:我们需要实现的仅仅是一个需要是就用用的迭代器!如果作为形参,那么每次调用都要用户负责对象的清理工作,甚至在第一调用之前出现了异常,可能出现无法清理的问题。同时,这样的设计还会导致每次获得的都是相同的IEnumerator。解决思路来源于:一个迭代器的代码段的真正执行是要到第一次MoveNext的,所以,实现迭代器的时候,形参可以“暂时为null"(当然更多的是理解上的,因为实现了迭代器在使用的时候形参必须是可以读取的),而接口有类似的功能,而且这里需要的功能是返回一个对象,那么就跟委托有点类似,委托太方便了,特别是匿名委托,特别是公共定义的匿名委托,只是返回一个对象,那么刚刚可以使用Func<out TResult>,

private static IEnumerable<string> GetFileReaderEnumerable(Func<StreamReader> reader)
        {   
            //考虑委托类型如何运行,枚举的好处来了:执行时才真正返回一个reader对象
            using(TextReader textReader = reader())
            {
                string line;
                while((line = textReader.ReadLine()) != null)
                {
                    yield return line;
                }
            }
        }

由于形参采用的是Func<out TResult>,且委托里面有一个外部变量捕获的特征,那么用一个方法包装一下,就可以传入外部的一些信息了

  static IEnumerable<string> ReadLines(string filename, Encoding fileencodeing)
        {
            return GetFileReaderEnumerable(delegate { return new StreamReader(filename, fileencodeing); });
        }
        public static void ReadAllData()
        {
            string filename = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, @"testdata.txt");
            if (File.Exists(filename))
            {
                IEnumerable<string> datalist = ReadLines(filename);
                foreach (string line in datalist)
                {
                    Console.WriteLine(line);
                }
            }
        }

如果再对必须传入一个Encoding不爽,那么可以使用重载搞个常用的方法

 static IEnumerable<string> ReadLines(string filename)
        {
            return ReadLines(filename, Encoding.UTF8);
        }

小结: 1 委托在功能上可以代替只有一个方法的接口

          2  匿名方法的外部变量捕获方便。

         3 实现了IEnumerable<T>就可以方便的遍历了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值