使用嵌套方法、yield return和using in combination时执行顺序奇怪
本文关键字:combination in 执行 顺序 using 嵌套 方法 return yield | 更新日期: 2023-09-27 18:16:21
我无法理解为什么Program.Fetch1
和Program.Fetch2
没有导致完全相同的执行顺序。唯一的区别是Program.Fetch1
调用Program.Fetch
来进行实际的取操作。
class Program
{
static IEnumerable<int> Fetch1()
{
using (Context c = new Context())
{
return Fetch(c);
}
}
static IEnumerable<int> Fetch(Context c)
{
foreach (int i in c.Fetch())
{
yield return i;
}
}
static IEnumerable<int> Fetch2()
{
using (Context c = new Context())
{
foreach (int i in c.Fetch())
{
yield return i;
}
}
}
static void Main(string[] args)
{
Console.WriteLine("Fetch1:");
foreach (int i in Fetch1())
{
Console.WriteLine(i);
}
Console.WriteLine("Fetch2:");
foreach (int i in Fetch2())
{
Console.WriteLine(i);
}
}
}
class Context : IDisposable
{
public void Dispose()
{
Console.WriteLine("Context.Dispose");
}
public IEnumerable<int> Fetch()
{
return new int[] { 1, 2 };
}
}
输出:Fetch1:
Context.Dispose
1
2
Fetch2:
1
2
Context.Dispose
我唯一的猜测是Context.Dispose
在Program.Fetch1
中首先被调用,因为using声明的作用域已经离开了。但Program.Fetch1
也是如此。为什么这些方法的行为不同呢?
更新:我的问题是在执行
这是因为这些选项实际上是不同的:
-
Fetch
和Fetch2
,使用yield
创建一个状态机,能够返回一个未物化的IEnumerable
。 - 在
Fetch1
中,您只需调用Fetch
并返回生成的状态机并处理上下文,而无需等待IEnumerable
实际实现。
基本上,不同之处在于,在Fetch2
中,你有一个延迟执行层(使用yield
),而在Fetch1
中,你没有,这意味着using作用域在你返回时立即结束。
您的Fetch
方法返回一个IEnumerable
。当它返回时,using块将处理上下文。然而,IEnumerable只是执行的承诺。它将执行。当你列举它的时候。这就是所谓的延迟执行。
因此,当您实际使用foreach枚举它时,枚举将发生并且Fetch
的代码将实际执行。在一个真实的程序中,你会得到错误,因为你的上下文已经被处理了。