前段时间了解到yield关键字,一直觉得还不错。今天给大家分享一下yield关键字的用法。yield return 返回集合不是一次性返回所有集合元素,而是一次调用返回一个元素。具体如何使用yield return 返回集合呢?我们一起往下面看吧。

yield return 和yield break:

我们看下平常循环返回集合的使用操作(返回1-100中的偶数):

  1. class Program
  2. {
  3. static private List<int> _numArray; //用来保存1-100 这100个整数
  4. Program() //构造函数。我们可以通过这个构造函数往待测试集合中存入1-100这100个测试数据
  5. {
  6. _numArray = new List<int>(); //给集合变量开始在堆内存上开内存,并且把内存首地址交给这个_numArray变量
  7.  
  8. for (int i = 1; i <= 100; i++)
  9. {
  10. _numArray.Add(i); //把1到100保存在集合当中方便操作
  11. }
  12. }
  13. static void Main(string[] args)
  14. {
  15. new Program();
  16. TestMethod();
  17. }
  18. //测试求1到100之间的全部偶数
  19. static public void TestMethod()
  20. {
  21. foreach (var item in GetAllEvenNumberOld())
  22. {
  23. Console.WriteLine(item); //输出偶数测试
  24. }
  25. }
  26. /// <summary>
  27. /// 使用平常返回集合方法
  28. /// </summary>
  29. /// <returns></returns>
  30. static IEnumerable<int> GetAllEvenNumberOld()
  31. {
  32. var listNum = new List<int>();
  33. foreach (int num in _numArray)
  34. {
  35. if (num % 2 == 0) //判断是不是偶数
  36. {
  37. listNum.Add(num); //返回当前偶数
  38. }
  39. }
  40. return listNum;
  41. }
  42. }

 

然后我们再看看使用yield return返回集合操作:

  1. class Program
  2. {
  3. static private List<int> _numArray; //用来保存1-100 这100个整数
  4. Program() //构造函数。我们可以通过这个构造函数往待测试集合中存入1-100这100个测试数据
  5. {
  6. _numArray = new List<int>(); //给集合变量开始在堆内存上开内存,并且把内存首地址交给这个_numArray变量
  7.  
  8. for (int i = 1; i <= 100; i++)
  9. {
  10. _numArray.Add(i); //把1到100保存在集合当中方便操作
  11. }
  12. }
  13. static void Main(string[] args)
  14. {
  15. new Program();
  16. TestMethod();
  17. }
  18. //测试求1到100之间的全部偶数
  19. static public void TestMethod()
  20. {
  21. foreach (var item in GetAllEvenNumber())
  22. {
  23. Console.WriteLine(item); //输出偶数测试
  24. }
  25. }
  26. //使用Yield Return情况下的方法
  27. static IEnumerable<int> GetAllEvenNumber()
  28. {
  29. foreach (int num in _numArray)
  30. {
  31. if (num % 2 == 0) //判断是不是偶数
  32. {
  33. yield return num; //返回当前偶数
  34. }
  35. }
  36. yield break; //当前集合已经遍历完毕,我们就跳出当前函数,其实你不加也可以
  37. //这个作用就是提前结束当前函数,就是说这个函数运行完毕了。
  38. }
  39. }

 

上面我们看到了yield return 的使用方法,那么这个与return返回集合有什么区别呢?我们看下面一个案例来进行分析:

我们首先先看通过returun返回集合的一个案例:

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. foreach (var item in GetNums())
  6. {
  7. Console.WriteLine($" common return:{item}");
  8. }
  9. }
  10. /// <summary>
  11. /// 平常return 返回集合
  12. /// </summary>
  13. /// <returns></returns>
  14. public static IEnumerable<int> GetNums()
  15. {
  16. var listNum = new List<int>();
  17. for (int i = 0; i < 10; i++)
  18. {
  19. Console.WriteLine($"yield return:{i}");
  20. listNum.Add(i);
  21. }
  22. return listNum;
  23. }
  24. }

通过代码的运行结果,我们可以看到这里返回的结果 yield return 和comment return是分成两边的。先执行完一个然后开始执行另外一个。不干涉。

我们接着看下使用yield return返回集合:

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. foreach (var item in GetNumsYield())
  6. {
  7. Console.WriteLine($" common return:{item}");
  8. }
  9. }
  10. /// <summary>
  11. /// 通过yield return 返回集合
  12. /// </summary>
  13. /// <returns></returns>
  14. public static IEnumerable<int> GetNumsYield()
  15. {
  16. for (int i = 0; i < 10; i++)
  17. {
  18. Console.WriteLine($"yield return:{i}");
  19. yield return i;
  20. }
  21. }
  22. }

我们看这个运行结果,这里yield return 和comment return 的输出完全交替了。这里说明是一次调用就返回了一个元素。

通过上面的案例我们可以发现,yield return 并不是等所有执行完了才一次性返回的。而是调用一次就返回一次结果的元素。这也就是按需供给。

我们已经大致了解了yield 的用法和它与平常的返回的区别。我们可以继续查看其运行原理。我们首先看这么一个案例(在0-10中随机返回五个数字):

我们通过SharpLab反编译其代码,我们进行查看发现yield具体详细实现:

 

我们看到yield内部含有一个迭代器。这样去实现的迭代遍历。同时包含_state字段、用来存储上一次的记录。_current包含当前的值、也通过_initialThreadId获取当前线程id。其中主要的方法是迭代器方法MoveNext()。我们根据反编译结果来实现一个与yiled相似的类:

 

  1. /// <summary>
  2. /// 解析yield并定义相似类
  3. /// </summary>
  4. public sealed class GetRandomNumbersClass : IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable, IEnumerator
  5. {
  6. public static Random r = new Random();
  7. /// <summary>
  8. /// 状态
  9. /// </summary>
  10. private int _state;
  11. /// <summary>
  12. ///储存当前值
  13. /// </summary>
  14. private int _current;
  15. /// <summary>
  16. /// 线程id
  17. /// </summary>
  18. private int _initialThreadId;
  19. /// <summary>
  20. /// 集合元素数量
  21. /// </summary>
  22. private int count;
  23. /// <summary>
  24. /// 集合元素数量
  25. /// </summary>
  26. public int _count;
  27. /// <summary>
  28. /// 当前指针
  29. /// </summary>
  30. private int i;
  31. int IEnumerator<int>.Current
  32. {
  33. [DebuggerHidden]
  34. get
  35. {
  36. return _current;
  37. }
  38. }
  39. object IEnumerator.Current
  40. {
  41. [DebuggerHidden]
  42. get
  43. {
  44. return _current;
  45. }
  46. }
  47. [DebuggerHidden]
  48. public GetRandomNumbersClass(int state)
  49. {
  50. this._state = state;
  51. _initialThreadId = Environment.CurrentManagedThreadId;
  52. }
  53. [DebuggerHidden]
  54. void IDisposable.Dispose()
  55. {
  56. }
  57. private bool MoveNext()
  58. {
  59. switch (_state)
  60. {
  61. default:
  62. return false;
  63. case 0:
  64. _state = -1;
  65. i = 0;
  66. break;
  67. case 1:
  68. _state = -1;
  69. i++;
  70. break;
  71. }
  72. if (i < count)
  73. {
  74. _current = r.Next(10);
  75. _state = 1;
  76. return true;
  77. }
  78. return false;
  79. }
  80. bool IEnumerator.MoveNext()
  81. {
  82. //ILSpy generated this explicit interface implementation from .override directive in MoveNext
  83. return this.MoveNext();
  84. }
  85. [DebuggerHidden]
  86. void IEnumerator.Reset()
  87. {
  88. throw new NotSupportedException();
  89. }
  90. [DebuggerHidden]
  91. public IEnumerator<int> GetEnumerator()
  92. {
  93. GetRandomNumbersClass _getRandom;
  94. if (_state == -2 && _initialThreadId == Environment.CurrentManagedThreadId)
  95. {
  96. _state = 0;
  97. _getRandom = this;
  98. }
  99. else
  100. {
  101. _getRandom = new GetRandomNumbersClass(0);
  102. }
  103. _getRandom.count = _count;
  104. return _getRandom;
  105. }
  106. [DebuggerHidden]
  107. IEnumerator IEnumerable.GetEnumerator()
  108. {
  109. return GetEnumerator();
  110. }
  111. [IteratorStateMachine(typeof(GetRandomNumbersClass))]
  112. private static IEnumerable<int> GetList(int count)
  113. {
  114. GetRandomNumbersClass getRandomNumbersClass = new GetRandomNumbersClass(-2);
  115. getRandomNumbersClass._count = count;
  116. return getRandomNumbersClass;
  117. }
  118. private static void Main(string[] args)
  119. {
  120. IEnumerator<int> enumerator = GetList(5).GetEnumerator();
  121. try
  122. {
  123. foreach (int item in GetList(5))
  124. Console.WriteLine(item);
  125. //while (enumerator.MoveNext())
  126. //{
  127. // int current = enumerator.Current;
  128. // Console.WriteLine(current);
  129. //}
  130. }
  131. finally
  132. {
  133. if (enumerator != null)
  134. {
  135. enumerator.Dispose();
  136. }
  137. }
  138. Console.ReadKey();
  139. }
  140. }

 

 


 

 用爱生活,你会使自己幸福!用爱工作,你会使很多人幸福! 

   欢迎大家扫描下方二维码,和我一起学习更多的知识

版权声明:本文为hulizhong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/hulizhong/p/11763956.html