前言
前段时间了解到 yield 关键字, 一直觉得还不错. 今天给大家分享一下 yield 关键字的用法. yield return 返回集合不是一次性返回所有集合元素, 而是一次调用返回一个元素. 具体如何使用 yield return 返回集合呢? 我们一起往下面看吧.
yield 使用介绍
yield return 和 yield break:
我们看下平常循环返回集合的使用操作 (返回 1-100 中的偶数):
- class Program
- {
- static private List<int> _numArray; // 用来保存 1-100 这 100 个整数
- Program() // 构造函数. 我们可以通过这个构造函数往待测试集合中存入 1-100 这 100 个测试数据
- {
- _numArray = new List<int>(); // 给集合变量开始在堆内存上开内存, 并且把内存首地址交给这个_numArray 变量
- for (int i = 1; i <= 100; i++)
- {
- _numArray.Add(i); // 把 1 到 100 保存在集合当中方便操作
- }
- }
- static void Main(string[] args)
- {
- new Program();
- TestMethod();
- }
- // 测试求 1 到 100 之间的全部偶数
- static public void TestMethod()
- {
- foreach (var item in GetAllEvenNumberOld())
- {
- Console.WriteLine(item); // 输出偶数测试
- }
- }
- /// <summary>
- /// 使用平常返回集合方法
- /// </summary>
- /// <returns></returns>
- static IEnumerable<int> GetAllEvenNumberOld()
- {
- var listNum = new List<int>();
- foreach (int num in _numArray)
- {
- if (num % 2 == 0) // 判断是不是偶数
- {
- listNum.Add(num); // 返回当前偶数
- }
- }
- return listNum;
- }
- }
然后我们再看看使用 yield return 返回集合操作:
- class Program
- {
- static private List<int> _numArray; // 用来保存 1-100 这 100 个整数
- Program() // 构造函数. 我们可以通过这个构造函数往待测试集合中存入 1-100 这 100 个测试数据
- {
- _numArray = new List<int>(); // 给集合变量开始在堆内存上开内存, 并且把内存首地址交给这个_numArray 变量
- for (int i = 1; i <= 100; i++)
- {
- _numArray.Add(i); // 把 1 到 100 保存在集合当中方便操作
- }
- }
- static void Main(string[] args)
- {
- new Program();
- TestMethod();
- }
- // 测试求 1 到 100 之间的全部偶数
- static public void TestMethod()
- {
- foreach (var item in GetAllEvenNumber())
- {
- Console.WriteLine(item); // 输出偶数测试
- }
- }
- // 使用 Yield Return 情况下的方法
- static IEnumerable<int> GetAllEvenNumber()
- {
- foreach (int num in _numArray)
- {
- if (num % 2 == 0) // 判断是不是偶数
- {
- yield return num; // 返回当前偶数
- }
- }
- yield break; // 当前集合已经遍历完毕, 我们就跳出当前函数, 其实你不加也可以
- // 这个作用就是提前结束当前函数, 就是说这个函数运行完毕了.
- }
- }
与平常 return 比较
上面我们看到了 yield return 的使用方法, 那么这个与 return 返回集合有什么区别呢? 我们看下面一个案例来进行分析:
我们首先先看通过 returun 返回集合的一个案例:
- class Program
- {
- static void Main(string[] args)
- {
- foreach (var item in GetNums())
- {
- Console.WriteLine($"common return:{item}");
- }
- }
- /// <summary>
- /// 平常 return 返回集合
- /// </summary>
- /// <returns></returns>
- public static IEnumerable<int> GetNums()
- {
- var listNum = new List<int>();
- for (int i = 0; i <10; i++)
- {
- Console.WriteLine($"yield return:{i}");
- listNum.Add(i);
- }
- return listNum;
- }
- }
通过代码的运行结果, 我们可以看到这里返回的结果 yield return 和 comment return 是分成两边的. 先执行完一个然后开始执行另外一个. 不干涉.
我们接着看下使用 yield return 返回集合:
- class Program
- {
- static void Main(string[] args)
- {
- foreach (var item in GetNumsYield())
- {
- Console.WriteLine($"common return:{item}");
- }
- }
- /// <summary>
- /// 通过 yield return 返回集合
- /// </summary>
- /// <returns></returns>
- public static IEnumerable<int> GetNumsYield()
- {
- for (int i = 0; i <10; i++)
- {
- Console.WriteLine($"yield return:{i}");
- yield return i;
- }
- }
- }
我们看这个运行结果, 这里 yield return 和 comment return 的输出完全交替了. 这里说明是一次调用就返回了一个元素.
通过上面的案例我们可以发现, yield return 并不是等所有执行完了才一次性返回的. 而是调用一次就返回一次结果的元素. 这也就是按需供给.
解析定义类
我们已经大致了解了 yield 的用法和它与平常的返回的区别. 我们可以继续查看其运行原理. 我们首先看这么一个案例 (在 0-10 中随机返回五个数字):
我们通过 SharpLab https://sharplab.io/ 反编译其代码, 我们进行查看发现 yield 具体详细实现:
我们看到 yield 内部含有一个迭代器. 这样去实现的迭代遍历. 同时包含_state 字段, 用来存储上一次的记录._current 包含当前的值, 也通过_initialThreadId 获取当前线程 id. 其中主要的方法是迭代器方法 MoveNext(). 我们根据反编译结果来实现一个与 yiled 相似的类:
- /// <summary>
- /// 解析 yield 并定义相似类
- /// </summary>
- public sealed class GetRandomNumbersClass : IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable, IEnumerator
- {
- public static Random r = new Random();
- /// <summary>
- /// 状态
- /// </summary>
- private int _state;
- /// <summary>
- /// 储存当前值
- /// </summary>
- private int _current;
- /// <summary>
- /// 线程 id
- /// </summary>
- private int _initialThreadId;
- /// <summary>
- /// 集合元素数量
- /// </summary>
- private int count;
- /// <summary>
- /// 集合元素数量
- /// </summary>
- public int _count;
- /// <summary>
- /// 当前指针
- /// </summary>
- private int i;
- int IEnumerator<int>.Current
- {
- [DebuggerHidden]
- get
- {
- return _current;
- }
- }
- object IEnumerator.Current
- {
- [DebuggerHidden]
- get
- {
- return _current;
- }
- }
- [DebuggerHidden]
- public GetRandomNumbersClass(int state)
- {
- this._state = state;
- _initialThreadId = Environment.CurrentManagedThreadId;
- }
- [DebuggerHidden]
- void IDisposable.Dispose()
- {
- }
- private bool MoveNext()
- {
- switch (_state)
- {
- default:
- return false;
- case 0:
- _state = -1;
- i = 0;
- break;
- case 1:
- _state = -1;
- i++;
- break;
- }
- if (i <count)
- {
- _current = r.Next(10);
- _state = 1;
- return true;
- }
- return false;
- }
- bool IEnumerator.MoveNext()
- {
- //ILSpy generated this explicit interface implementation from .override directive in MoveNext
- return this.MoveNext();
- }
- [DebuggerHidden]
- void IEnumerator.Reset()
- {
- throw new NotSupportedException();
- }
- [DebuggerHidden]
- public IEnumerator<int> GetEnumerator()
- {
- GetRandomNumbersClass _getRandom;
- if (_state == -2 && _initialThreadId == Environment.CurrentManagedThreadId)
- {
- _state = 0;
- _getRandom = this;
- }
- else
- {
- _getRandom = new GetRandomNumbersClass(0);
- }
- _getRandom.count = _count;
- return _getRandom;
- }
- [DebuggerHidden]
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- [IteratorStateMachine(typeof(GetRandomNumbersClass))]
- private static IEnumerable<int> GetList(int count)
- {
- GetRandomNumbersClass getRandomNumbersClass = new GetRandomNumbersClass(-2);
- getRandomNumbersClass._count = count;
- return getRandomNumbersClass;
- }
- private static void Main(string[] args)
- {
- IEnumerator<int> enumerator = GetList(5).GetEnumerator();
- try
- {
- foreach (int item in GetList(5))
- Console.WriteLine(item);
- //while (enumerator.MoveNext())
- //{
- // int current = enumerator.Current;
- // Console.WriteLine(current);
- //}
- }
- finally
- {
- if (enumerator != null)
- {
- enumerator.Dispose();
- }
- }
- Console.ReadKey();
- }
- }
用爱生活, 你会使自己幸福! 用爱工作, 你会使很多人幸福!
C# 基础知识详解系列
欢迎大家扫描下方二维码, 和我一起学习更多的知识
来源: https://www.cnblogs.com/hulizhong/p/11763956.html