C#yield return和yield break

C#yield return和yield break

晚上好,各位。今天结合书中所讲和MSDN所查,聊下yield关键字,它是我们简化迭代器的关键。

  如果你在语句中使用了yield关键字,则意味着它在其中出现的方法、运算符或get访问器是迭代器,通过使用yield定义迭代器,可在实现自定义集合类型的IEnumerable和IEnumerator模式时无需显示类(保留枚举状态类),使用yield有两种形式,如下

1 yield return 表达式

2 yield break

  先说明一下yield return语句,每一次返回一个元素。通过foreach语句或LINQ查询来使用迭代器方法。foreach循环的每次迭代都会调用迭代器方法,会保存当前返回的状态。

复制代码
 1 static void Main(string[] args)

 2 {

 3     foreach (int i in GetValues())

 4     {

 5         Console.WriteLine(i);

 6     }

 7     Console.ReadKey();

 8 }

 9 

10 static IEnumerable<int> GetValues()

11 {

12     yield return 1;

13     yield return 2;

14     yield return 3;

15 }
复制代码

  不能将yield return语句放在try-catch之中,但可以把它放在try-finally之中。yield return有两个特点:1.返回类型必须是IEnumerable、IEnumerator、IEnumerator<T>、IEnumerable<T>.2.不能使用ref和out修饰符。在匿名方法和不安全代码中不能包含yield return和yield break。下面我们使用yield return来简化上一篇中对Student的迭代,重新个性了Queue<T>这个泛型类,如下

复制代码
 1 class Queue<T> : IEnumerable<T> where T : class

 2 {

 3     public List<T> objects = new List<T>();

 4     int startPoint = 0;

 5     public Queue(List<T> list)

 6     {

 7         objects = list;

 8     }

 9 

10     //实现从IEnumerable中的GetEnumerator方法

11     /*

12         个人觉得这个方法在迭代中只会调用一次,不然每次都返回一个新的QueueIterator<T>对象,位置记录都会重置为-1

13     */

14     public IEnumerator<T> GetEnumerator()

15     {

16         //return new QueueIterator<T>(this);  

17         for (int index = 0; index < objects.Count; index++)

18         {

19             

20             yield return objects[(index + startPoint) % objects.Count];

21         }

22     }

23 

24     IEnumerator IEnumerable.GetEnumerator()

25     {

26         throw new NotImplementedException();

27     }

28 }
复制代码

  代码到了yield return时,返回objects中一个合适的元素,并保存当前的状态,等下一次调用时从记数的位置开始。在使用程序中,如下,和原先一样。

复制代码
 1 List<Student> list = new List<Student> {

 2     new Student("СA"),

 3     new Student("СB"),

 4     new Student("СC"),

 5     new Student("СD"),

 6     new Student("СE")

 7 };

 8 ConsoleDemo.Chapter6.Queue<Student> lq = new Chapter6.Queue<Student>(list);

 9 

10 foreach (var obj in lq)

11 {

12     obj.SayName();

13 }
复制代码

  可以看到结果都是迭代的打印每一个元素的名字。在来说下return break,从break中可以看中,是跳出,那意思就应该上跳出迭代,如

复制代码
 1 class Program

 2 {

 3     static void Main(string[] args)

 4     {

 5 

 6         foreach (int i in GetValues())

 7         {

 8             Console.WriteLine(i);

 9         }

10         Console.ReadKey();

11     }

12 

13     static IEnumerable<int> GetValues()

14     {

15         yield return 1;

16         yield return 2;

17         yield break;

18         yield return 3;

19     }

20 }
复制代码

  到了yield return 2时,下一语句是yield break,则在控制台只会打印1,2,因为在打印3之前就使用yield break跳出迭代了。

  下面我们使用一个实际点的读文件的例子。新建一个文本demo.txt,内容如下

复制代码
 1 1

 2 2

 3 3

 4 4

 5 5

 6 6

 7 7

 8 8

 9 9

10 0
复制代码

  代码如下

复制代码
 1 class Program

 2 {

 3     static void Main(string[] args)

 4     {

 5         foreach(var line in ReadLines("./demo.txt"))

 6         {

 7             Console.WriteLine(line);

 8         }

 9         Console.ReadKey();

10     }

11 

12     static IEnumerable<string> ReadLines(string path)

13     {

14         string line;

15         TextReader tr = File.OpenText(path);

16         while ((line = tr.ReadLine()) != null)

17         {

18             yield return line;

19         }

20     }

21 }
复制代码

  当然其实File中的表态方法是有ReadLines方法的,返回的也是IEnumerable<string>,看来我们是多此一举了,不过也不错,知道了一些yield的使用,原理的那些真心不敢写,写了自己也看不懂,希望以后能用自己组织语言,解译那些原理。

  请斧正。

 
分类:  深入理解C#

你可能感兴趣的:(return)