在.Net中yield是一个关键字,在一些项目中也常用到。下面用一个最简单的例子来说明它的使用场景。以下两段代码的执行效果是一样的:
public IEnumerable<int> GetCollection1()
{
IList<int> list = new List<int>();
for(int i = 0; i < 10; i++)
{
list.Add(i);
}
return list;
}
public IEnumerable<int> GetCollection2()
{
for (int i = 0; i < 10; i++)
{
yield return i;
}
}
这就是yield独到之处,它不需要容器就可以直接返回数据集,那这样的话性能会提高么?答案是肯定的,可以做以下测试,需要注意的是使用yield时没有使用数据集只是返回引用地址,所以只在遍历的过程中才能真正意义上看到它的效率。于是我们的测试代码如下:
[Test]
public void YelidTest()
{
Stopwatch sw = new Stopwatch();
sw.Start();
var r1 = GetCollection1();
foreach(var i in r1)
{
}
sw.Stop();
Console.WriteLine($"Collection1:{sw.ElapsedMilliseconds}");
sw.Restart();
var r2 = GetCollection2();
foreach (var i in r2)
{
}
sw.Stop();
Console.WriteLine($"Collection2:{sw.ElapsedMilliseconds}");
}
两个方法也加大了数据范围如下:
public IEnumerable<int> GetCollection1()
{
IList<int> list = new List<int>();
for (int i = 0; i < 1000000; i++)
{
list.Add(i);
}
return list;
}
public IEnumerable<int> GetCollection2()
{
for (int i = 0; i < 1000000; i++)
{
yield return i;
}
}
最终输出:Collection1:1998 Collection2:1411
我使用的是在NetCore中的单元测试,在framework下同理。这里只是使用int类型测试如果使用复杂的引用类型更能体现出他们的差距。
另外还有yield break;的用法,简单示例如下:
yield return 1;
yield return 2;
yield return 3;
yield break;
yield return 4;
这种情况下4不会被包含在结果集中。
最后是yield的使用限制
不能将 yield return 语句置于 try-catch 块中。 可将 yield return 语句置于 try-finally 语句的 try 块中。
可将 yield break 语句置于 try 块或 catch 块中,但不能将其置于 finally 块中。
如果 foreach 主体(在迭代器方法之外)引发异常,则将执行迭代器方法中的 finally 块。
原创内容禁止转载!
推荐文章: