yield关键字是微软的一个语法糖,使用它可以让我们的代码具有更高可读性和更好性能。有了yield关键字,当我们需要返回IEnumerable类型的时候,直接yield返回数据就可以了。也不用new一个list,或其他类型。 :::info 如果要通过计算并返回一个集合数据,传统的办法就是建一个IEnumerable集合,然后把计算出来的数据装到这个集合里面再返回。如果这个计算很慢,一秒钟算出一个值,10个值算出来再返回展示给用户,相当于有10秒钟,用户不知道程序在干嘛。而用yield return,每秒钟就能给用户提供一个值。虽然全部完成也要10秒钟,但是体验感不同。 :::
yield语法
yield return <expression>;
yield break;
- yield return语句返回集合的一个元素,并移动到下一个元素上
- yield break可以停止迭代,相当于正常代码块的 return 语句(迭代器中直接使用 return 是非法的)
- 包含yield语句的方法或属性是迭代器。迭代器必须满足以下要求:
- 返回类型必须是IEnumerable、IEnumerable
、IEnumerator或 IEnumerator - 它不能有任何ref或out参数
- 返回类型必须是IEnumerable、IEnumerable
- yield return语句不能位于try-catch块。
- yield return语句可以位于try-finally的try块。
yield break语句可以位于try块或catch块,但是不能位于finally块。
例子
static void Main(string[] args)
{
//可用一个变量来装,也可以直接迭代
foreach (var item in yield1(100))
{
Console.WriteLine(item);
}
Console.ReadLine();
}
//用法1:每个0.5秒打印返回一个元素
static IEnumerable<int> yield1(int n)
{
for(int i = 1; i < n; i++)
{
if (i % 88 == 0)
{
yield break;
}
if (i % 2 == 0)
{
Thread.Sleep(500);
yield return i;
}
}
}
//用法2:打印123的时候每隔一秒打印一次
static IEnumerable<int> yield2()
{
Thread.Sleep(1000);
yield return 1;
Thread.Sleep(1000);
yield return 22;
Thread.Sleep(1000);
yield return 333;
yield return 4444;
yield return 55555;
yield return 666666;
}
关于yield的性能比较
static void Main(string[] args)
{
DateTime t1 =DateTime.Now;
foreach (var item in listYieldReturn())
{
//Console.WriteLine(item);
}
DateTime t2 = DateTime.Now;
Console.WriteLine("耗时:"+(t2-t1).TotalMilliseconds);
}
//耗时1450ms,进程占用内存12MB
static IEnumerable<string> listYieldReturn()
{
for (int i = 0; i < 100000000; i++)
{
yield return "这是一段字符串";
}
}
//耗时3250ms,进程占用内存2.1GB
//需要把Main方法里面的东西封装到一个返回void的方法里面。Main里面调用这个方法。之后再GC.Collect(GC.MaxGeneration);才能回收掉这2G的垃圾
static IEnumerable<string> listReturn()
{
List<string> list = new List<string>();
for(int i = 0; i < 100000000; i++)
{
list.Add("这是一段字符串");
}
return list;
}