zoukankan      html  css  js  c++  java
  • 6.2 C# 2:利用 yield 语句简化迭代器

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             object[] values = new object[] { "a", "b", "c", "d", "e" };
     6             IterationSample sample = new IterationSample(values, 3);
     7             foreach (var item in sample)
     8             {
     9                 Console.WriteLine(item);
    10             }
    11             Console.ReadKey();
    12         }
    13     }
    14     public class IterationSample : IEnumerable
    15     {
    16         public object[] values;
    17         int startPoint;
    18         public IterationSample(object[] values, int startingPoint)
    19         {
    20             this.values = values;
    21             this.startPoint = startingPoint;
    22         }
    23         public IEnumerator GetEnumerator()
    24         {
    25             //return new IterationSampleIterator(this);
    26             for (int index = 0; index < values.Length; index++)
    27             {
    28                 yield return values[(index + startPoint) % values.Length];
    29             } 
    30         }
    31     }
    32     public class IterationSampleIterator : IEnumerator
    33     {
    34         IterationSample parent;
    35         int position;
    36         public IterationSampleIterator(IterationSample parent)
    37         {
    38             this.parent = parent;
    39             this.position = -1;
    40         }
    41         public object Current
    42         {
    43             get
    44             {
    45                 if (position == -1 || position == parent.values.Length)
    46                 {
    47                     throw new InvalidOperationException();
    48                 }
    49                 int index = position + parent.values.Length;
    50                 index = index % parent.values.Length;
    51                 return parent.values[index];
    52             }
    53         }
    54 
    55         public bool MoveNext()
    56         {
    57             if (position != parent.values.Length)
    58             {
    59                 position++;
    60             }
    61             return position < parent.values.Length;
    62         }
    63 
    64         public void Reset()
    65         {
    66             position = -1;
    67         }
    68     }

    6.2.2 观察迭代器的工作流程

     1     class Program
     2     {
     3         static readonly string Padding = new string(' ', 30);
     4         static void Main(string[] args)
     5         {
     6             IEnumerable<int> iterable = CreatteEnumerable(Padding);
     7             IEnumerator<int> iterator = iterable.GetEnumerator();
     8             Console.WriteLine("starting iterate");
     9 
    10             while (true)
    11             {
    12                 Console.WriteLine("=======================================");
    13                 Console.WriteLine("calling MoveNext()");
    14                 bool result = iterator.MoveNext();
    15                 Console.WriteLine("moveNext result = {0}", result);
    16                 if (!result)
    17                     break;
    18                 Console.WriteLine("fetching current");
    19                 Console.WriteLine("current result = {0}", iterator.Current);
    20             }
    21 
    22             Console.ReadKey();
    23         }
    24         static IEnumerable<int> CreatteEnumerable(string Padding)
    25         {
    26             Console.WriteLine("{0} start of createEnumerbale padding", Padding);
    27 
    28             for (int i = 0; i < 3; i++)
    29             {
    30                 Console.WriteLine("{0} about to yield {1}", Padding, i);
    31                 yield return i;
    32                 Console.WriteLine("{0} after padding", Padding);
    33             }
    34             Console.WriteLine("{0} yield final value ", Padding);
    35             yield return -1;
    36             Console.WriteLine("{0} end of createEnumerable();", Padding);
    37         }
    38         /*
    39         
    40         starting iterate
    41         =======================================
    42         calling MoveNext()
    43                                        start of createEnumerbale padding
    44                                        about to yield 0
    45         moveNext result = True
    46         fetching current
    47         current result = 0
    48         =======================================
    49         calling MoveNext()
    50                                        after padding
    51                                        about to yield 1
    52         moveNext result = True
    53         fetching current
    54         current result = 1
    55         =======================================
    56         calling MoveNext()
    57                                        after padding
    58                                        about to yield 2
    59         moveNext result = True
    60         fetching current
    61         current result = 2
    62         =======================================
    63         calling MoveNext()
    64                                        after padding
    65                                        yield final value
    66         moveNext result = True
    67         fetching current
    68         current result = -1
    69         =======================================
    70         calling MoveNext()
    71                                        end of createEnumerable();
    72         moveNext result = False
    73 
    74          */
    75     }

     6.2.3 进一步了解迭代器执行流程

    1. 使用 yield break 结束迭代器的执行

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             DateTime stop = DateTime.Now.AddSeconds(2);
     6             foreach (var item in CountWithTimeLimit(stop))
     7             {
     8                 Console.WriteLine("received {0}", item);
     9                 Thread.Sleep(300);
    10             }
    11             Console.ReadKey();
    12         }
    13         static IEnumerable<int> CountWithTimeLimit(DateTime limit)
    14         {
    15             for (int i = 0; i < 100; i++)
    16             {
    17                 if (DateTime.Now >= limit)
    18                 {
    19                     yield break;
    20                 }
    21                 yield return i;
    22             }
    23         }
    24     }

    2.  finally 代码块的执行

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             DateTime stop = DateTime.Now.AddSeconds(2);
     6             foreach (var item in CountWithTimeLimit(stop))
     7             {
     8                 Console.WriteLine("received {0}", item);
     9                 if (item > 3)
    10                 {
    11                     Console.WriteLine("returning");
    12                     return;
    13                 }
    14                 Thread.Sleep(300);
    15             }
    16             Console.ReadKey();
    17         }
    18         static IEnumerable<int> CountWithTimeLimit(DateTime limit)
    19         {
    20             try
    21             {
    22                 for (int i = 0; i < 100; i++)
    23                 {
    24                     if (DateTime.Now >= limit)
    25                     {
    26                         yield break;
    27                     }
    28                     yield return i;
    29                 }
    30             }
    31             finally
    32             {
    33                 Console.WriteLine("stopping");
    34                 Console.ReadKey();
    35             }
    36         }
    37         /*
    38         received 0
    39         received 1
    40         received 2
    41         received 3
    42         received 4
    43         returning
    44         stopping
    45          */
    46     }

    foreach 会在它自己的 finally 代码块中调用 IEnumerator 所提供的Dispose 方法(就像 using 语句)。
    当迭代器完成迭代之前,你如果调用由迭代器代码块创建的迭代器上的 Dispose ,
    那么状态机就会执行在代码当前“暂停”位置范围内的任何 finally 代码块。
    这个解释复杂且有点详细,但结果却很容易描述:只要调用者使用了 foreach 循环,迭代器块中的 finally 将按照你期望的方式工作。

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             DateTime stop = DateTime.Now.AddSeconds(2);
     6             IEnumerable<int> iterable = CountWithTimeLimit(stop);
     7             IEnumerator<int> iterator = iterable.GetEnumerator();
     8 
     9             iterator.MoveNext();
    10             Console.WriteLine("received {0}", iterator.Current);
    11 
    12             iterator.MoveNext();
    13             Console.WriteLine("received {0}", iterator.Current);
    14 
    15             Console.ReadKey();
    16         }
    17         static IEnumerable<int> CountWithTimeLimit(DateTime limit)
    18         {
    19             try
    20             {
    21                 for (int i = 0; i < 100; i++)
    22                 {
    23                     if (DateTime.Now >= limit)
    24                     {
    25                         yield break;
    26                     }
    27                     yield return i;
    28                 }
    29             }
    30             finally
    31             {
    32                 Console.WriteLine("stopping");
    33                 Console.ReadKey();
    34             }
    35         }
    36         /*
    37         received 0
    38         received 1
    39          */
    40     }

    幸好,作为开发人员我们不需要太关心编译器是如何解决这些问题的。不过,关于实现中的以下一些奇特之处还是值得了解的:
     在第一次调用 MoveNext 之前, Current 属性总是返回迭代器产生类型的默认值;
     在 MoveNext 返回 false 之后, Current 属性总是返回最后的生成值;
     Reset 总是抛出异常,而不像我们手动实现的重置过程那样,为了遵循语言规范,这是必要的行为;
     嵌套类总是实现 IEnumerator 的泛型形式和非泛型形式(提供给泛型和非泛型的IEnumerable 所用)。

    6.3.2 迭代文件中的行

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             string fileName = string.Format(@"{0}aaa.txt", AppDomain.CurrentDomain.BaseDirectory);
     6             foreach (var item in ReadLines(fileName))
     7             {
     8                 Console.WriteLine(item);
     9             }
    10 
    11             Console.ReadKey();
    12         }
    13         static IEnumerable<string> ReadLines(string fileName)
    14         {
    15             using (TextReader reader = File.OpenText(fileName))
    16             {
    17                 string line;
    18                 while ((line = reader.ReadLine()) != null)
    19                 {
    20                     yield return line;
    21                 }
    22             }
    23         }
    24     }

     6.3.3 使用迭代器块和谓词对项进行延迟过滤

     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             string fileName = string.Format(@"{0}aaa.txt", AppDomain.CurrentDomain.BaseDirectory);
     6 
     7             IEnumerable<string> lines = ReadLines(fileName);
     8             Predicate<string> predicate = line => line.StartsWith("using");
     9 
    10             foreach (var item in Where(lines, predicate))
    11             {
    12                 Console.WriteLine(item);
    13             }
    14 
    15             Console.ReadKey();
    16         }
    17         public static IEnumerable<T> Where<T>(IEnumerable<T> source, Predicate<T> predicate)
    18         {
    19             if (source.IsNull() || predicate.IsNull())
    20                 throw new ArgumentException();
    21 
    22             return WhereImpl(source, predicate);
    23         }
    24         private static IEnumerable<T> WhereImpl<T>(IEnumerable<T> source, Predicate<T> predicate)
    25         {
    26             foreach (T item in source)
    27             {
    28                 if (predicate(item))
    29                 {
    30                     yield return item;
    31                 }
    32             }
    33         }
    34         static IEnumerable<string> ReadLines(string fileName)
    35         {
    36             return ReadLines(() => { return File.OpenText(fileName); });
    37         }
    38         static IEnumerable<string> ReadLines(Func<TextReader> provider)
    39         {
    40             using (TextReader reader = provider())
    41             {
    42                 string line;
    43                 while ((line = reader.ReadLine()) != null)
    44                 {
    45                     yield return line;
    46                 }
    47             }
    48         }
    49     }
  • 相关阅读:
    PHP定时备份MySQL,mysqldump语法大全
    虚拟机拷贝之后,发现系统内的开机自启动的nginx,不能自启动了
    八:二叉搜索树的后序遍历
    配置Ubuntu开发环境
    poj 1147 Binary codes
    test
    Python标准库:内置函数reversed(seq)
    Matplotlib 工具包 使用教程索引
    6大设计原则(1):单一职责原则
    hdu 4104
  • 原文地址:https://www.cnblogs.com/kikyoqiang/p/10015675.html
Copyright © 2011-2022 走看看