我无法理解为什么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
,因为已使用声明的范围。但对于Program.Fetch1
也是如此。那么为什么这些方法表现不同呢?
更新:我的问题与yield return statement inside a using() { } block Disposes before executing
重复答案 0 :(得分:6)
那是因为这些选项实际上是不同的:
Fetch
和Fetch2
使用yield
创建状态机,以便能够返回未实现的IEnumerable
。Fetch1
中,您只需调用Fetch
并返回生成的状态机并处理上下文,而无需等待IEnumerable
实际实现。基本上,不同之处在于,在Fetch2
中您有一层延迟执行(使用yield
)而在Fetch1
中您没有,这意味着使用范围结束你什么时候回来。
答案 1 :(得分:2)
您的Fetch
方法会返回IEnumerable
。返回此值时,您的using块将处理上下文。但是,IEnumerable只是执行的 promise 。它将执行。当你枚举它。这称为deferred execution。
因此,当您实际使用foreach枚举它时,将进行枚举,并且Fetch
的代码将实际执行。在实际程序中,由于您的上下文已被处理,您将收到错误。