C# 为什么可以';t a';继续';语句必须位于';最后';块
我没有问题;我只是好奇。想象一下以下场景:C# 为什么可以';t a';继续';语句必须位于';最后';块,c#,.net,C#,.net,我没有问题;我只是好奇。想象一下以下场景: foreach (var foo in list) { try { //Some code } catch (Exception) { //Some more code } finally { continue; } } 这不会编译,因为它会引发: 控件不能离开finally子句的主体 为什么?这里有一个可靠的来源: contin
foreach (var foo in list)
{
try
{
//Some code
}
catch (Exception)
{
//Some more code
}
finally
{
continue;
}
}
这不会编译,因为它会引发:
控件不能离开finally子句的主体
为什么?这里有一个可靠的来源: continue语句不能退出finally块(第8.10节)。什么时候 continue语句出现在finally块中,finally块是 continue语句必须位于同一finally块中;否则,一个 发生编译时错误 它取自MSDN 文件说: finally块的语句总是在控件离开时执行 试试这句话。无论控制权转移是否作为 正常执行的结果,作为执行中断的结果, continue、goto或return语句,或作为传播 try语句中的异常。如果在过程中引发异常 执行finally块时,异常会传播到下一个 包含try语句。如果另一个异常正在处理中 在传播时,该异常将丢失。传播过程 在throw语句的描述(第8.9.5节)中进一步讨论了一个异常
从这里开始。通常
continue
在finally
块中使用时没有意义。看看这个:
foreach (var item in list)
{
try
{
throw new Exception();
}
finally{
//doesn't make sense as we are after exception
continue;
}
}
不能离开finally块的主体。这包括break、return和continue关键字 “这不会编译,我认为它完全有意义” 嗯,我想没有 如果您确实有
catch(Exception)
,那么您就不需要finally(甚至可能不需要continue
)
当您有更现实的
捕获(SomeException)
时,如果未捕获异常,会发生什么?您的continue
想要走一条路,异常处理另一条路 你可能认为它有意义,但实际上它没有意义
foreach (var v in List)
{
try
{
//Some code
}
catch (Exception)
{
//Some more code
break; or return;
}
finally
{
continue;
}
}
当抛出异常时,您打算如何执行中断或继续?C#编译器团队不希望通过假设中断
或继续
来自行做出决定。相反,他们决定抱怨开发人员将控制权从最终块
转移的情况不明确
因此,开发人员的工作是清楚地说明他打算做什么,而不是假设其他事情
我希望您理解为什么这不能编译
最后
无论是否引发异常,块都会运行。如果抛出异常,continue
会做什么?无法继续执行循环,因为未捕获的异常会将控制权转移到另一个函数
即使没有引发异常,finally
也会在try/catch块内的其他控制传输语句运行时运行,例如return
,这会带来同样的问题
简而言之,使用finally
的语义,允许将控制从finally
块内部转移到块外部是没有意义的
用一些替代的语义来支持这一点会更加混乱而不是有帮助,因为有一些简单的变通方法可以使预期的行为方式更加清晰。所以你会犯错误,被迫正确地思考你的问题。这是C#中普遍存在的“把你扔进成功的深渊”的想法
如果要忽略异常(通常是一个坏主意)并继续执行循环,请使用catch-all块:
foreach ( var in list )
{
try{
//some code
}catch{
continue;
}
}
如果只想在没有引发未捕获异常的情况下
继续
,只需将继续
放在try块之外。最后块可以在等待重试的异常情况下执行。如果不重新触发异常,就能够退出块(通过continue
或其他方式)是没有意义的
如果不管发生什么情况,您都想继续循环,那么不需要finally语句:只捕获异常,不要重复。正如其他人所说,但重点是异常,它实际上是关于传输控制的模糊处理 在您的脑海中,您可能会想到这样一个场景:
public static object SafeMethod()
{
foreach(var item in list)
{
try
{
try
{
//do something that won't transfer control outside
}
catch
{
//catch everything to not throw exceptions
}
}
finally
{
if (someCondition)
//no exception will be thrown,
//so theoretically this could work
continue;
}
}
return someValue;
}
var exceptions = new List<Exception>();
foreach (var foo in list) {
try {
// some code
} catch (InvalidOperationException ex) {
// handle specific exception
continue;
} catch (Exception ex) {
exceptions.Add(ex);
continue;
}
// some more code
}
if (exceptions.Any()) {
throw new AggregateException(exceptions);
}
理论上,您可以跟踪控制流并说,是的,这是“ok”。不会引发异常,也不会传输任何控件。但C#语言设计师们还考虑了其他问题
抛出的异常
可怕的后藤
回归
分手
总之,是的,虽然在控制权未转移的情况下使用
continue
的可能性很小,但大多数情况下都涉及异常或return
块。语言设计者认为这太模糊了,而且(可能)不可能在编译时确保您的continue
仅在控制流未被传输的情况下使用。最后,无论是否引发未捕获的异常,都会运行。其他人已经解释了为什么这使得继续不合逻辑,但这里有一个替代方案,它遵循了这段代码所要求的精神。基本上,最后{continue;}
是说:
如果捕获到异常,请继续
当存在未捕获的异常时,允许抛出它们,但仍继续
(1) 可以通过将continue
放在每个catch
的末尾来满足,并且(2)可以通过存储未捕获的异常来满足,这些异常将在以后抛出。你可以这样写:
public static object SafeMethod()
{
foreach(var item in list)
{
try
{
try
{
//do something that won't transfer control outside
}
catch
{
//catch everything to not throw exceptions
}
}
finally
{
if (someCondition)
//no exception will be thrown,
//so theoretically this could work
continue;
}
}
return someValue;
}
var exceptions = new List<Exception>();
foreach (var foo in list) {
try {
// some code
} catch (InvalidOperationException ex) {
// handle specific exception
continue;
} catch (Exception ex) {
exceptions.Add(ex);
continue;
}
// some more code
}
if (exceptions.Any()) {
throw new AggregateException(exceptions);
}
var异常=新列表();
foreach(列表中的变量foo){
试一试{
//一些代码
}捕获(无效操作异常ex){
//特定于句柄
public static void Break()
{
foreach(var item in list)
{
try
{
break;
}
finally
{
continue;
}
}
}
var exceptions = new List<Exception>();
foreach (var foo in list) {
try {
// some code
} catch (InvalidOperationException ex) {
// handle specific exception
continue;
} catch (Exception ex) {
exceptions.Add(ex);
continue;
}
// some more code
}
if (exceptions.Any()) {
throw new AggregateException(exceptions);
}