Lir*_*ron 5 c# yield coroutine try-finally
如果我有一个如下的协程,那么finally块中的代码会被调用吗?
public IEnumerator MyCoroutine(int input)
{
try
{
if(input > 10)
{
Console.WriteLine("Can't count that high.");
yield break;
}
Console.WriteLine("Counting:");
for(int i = 0; i < input; i++)
{
Console.WriteLine(i.ToString());
yield return null;
}
}
finally
{
Console.WriteLine("Finally!");
}
}
Run Code Online (Sandbox Code Playgroud)
Chr*_*low 19
只要迭代器/枚举器被正确放置(IDisposable.Dispose()
被称为),那么是:
无论try块如何退出,控制总是传递给finally块.
http://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx
但是,要小心Dispose()
确实被称为,否则你最多可能会得到意想不到的结果.有关此现象的更多信息以及需要注意的一些问题,请查看此博客文章:
(感谢Scott B提供的链接,因为每个人似乎都错过了它所在的答案)
另外:
yield return语句不能位于try-catch块内的任何位置.如果try块后跟finally块,它可以位于try块中.
http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
sup*_*cat 14
到目前为止,所有的答案都省略了一个至关重要的细节:一个finally
包含一个yield return
将执行的块的代码if if和when在执行IDisposable.Dispose
它的iterator/enumerator上调用yield return
.如果外部代码调用GetEnumerator()
迭代器然后调用,MoveNext()
直到迭代器yield return
在finally
块内执行,然后外部代码放弃枚举器而不调用Dispose
,则finally
块中的代码将不会运行.根据迭代器正在做什么,它可能被垃圾收集器湮灭(虽然没有机会清理任何外部资源),或者它可能永久或半永久地根据内存泄漏(如果,例如,它将一个lambda表达式附加到一个长期存在的对象的事件处理程序中.
请注意,虽然vb和c#都非常适合确保foreach
循环将调用Dispose
枚举器,但是可以通过GetEnumerator()
显式调用来使用迭代器,并且有些代码可能无需调用就可以执行此操作Dispose()
.迭代器无法做到这一点,但任何编写迭代器的人都需要意识到这种可能性.