[英]Why can't a 'continue' statement be inside a 'finally' block?
我沒問題 我只是好奇。 想象以下情況:
foreach (var foo in list)
{
try
{
//Some code
}
catch (Exception)
{
//Some more code
}
finally
{
continue;
}
}
這不會編譯,因為它會引起編譯器錯誤CS0157 :
控制不能離開finally子句的主體
為什么?
不管是否引發異常, finally
塊都會運行。 如果引發異常,該怎么辦將continue
? 您無法繼續執行循環,因為未捕獲的異常會將控制權轉移到另一個函數。
即使沒有拋出異常,try / catch塊中的其他控件傳輸語句運行(例如return
時, finally
也會finally
運行,例如,這會帶來相同的問題。
簡而言之,使用finally
的語義,不允許將控制權從finally
塊內部轉移到其外部。
用一些替代的語義來支持此方法比有用的方法更令人困惑,因為有一些簡單的變通方法可以使預期的行為更清晰。 因此,您會得到一個錯誤,並被迫正確考慮您的問題。 這是C#中普遍存在的“使您陷入成功的陷阱”的想法。
如果您想忽略異常(通常不是一個壞主意)並繼續執行循環,請使用catch all塊:
foreach ( var in list )
{
try{
//some code
}catch{
continue;
}
}
如果你想continue
,只有當沒有捕獲的異常拋出,只是把continue
在try塊外。
這是可靠的來源:
Continue語句不能退出finally塊(第8.10節)。 當在finally塊內出現continue語句時,continue語句的目標必須在相同的finally塊內。 否則,將發生編譯時錯誤。
它取自MSDN, 8.9.2繼續聲明 。
該文檔說:
當控制離開try語句時,總是執行finally塊的語句。 無論是由於正常執行,由於執行break,continue,goto或return語句,還是由於在try語句中傳播異常而發生了控制轉移,都是如此。 如果在執行finally塊期間引發了異常,則該異常將傳播到下一個封閉的try語句。 如果另一個異常正在傳播中,則該異常將丟失。 在throw語句的描述中將進一步討論傳播異常的過程(第8.9.5節)。
從這里8.10 try語句 。
您可能認為這很有意義,但實際上卻沒有任何意義 。
foreach (var v in List)
{
try
{
//Some code
}
catch (Exception)
{
//Some more code
break; or return;
}
finally
{
continue;
}
}
當拋出異常時,您打算做什么休息或繼續 ? C#編譯器團隊不希望通過假設作出自己的決定break
或continue
。 取而代之的是,他們決定抱怨開發者的情況對於從finally block
轉移控制權將是模棱兩可的。
因此,開發人員的工作是清楚地陳述自己打算做什么,而不是讓編譯器假設其他事情。
希望您能理解為什么它無法編譯!
正如其他人所述,但專注於異常,它實際上是關於轉移控制權的模棱兩可的處理。
在您的腦海中,您可能會想到這樣的情況:
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;
}
從理論上講,您可以跟蹤控制流並說“是的”。 沒有引發異常,沒有控制權被轉移。 但是C#語言設計人員還要考慮其他問題。
public static void Exception()
{
try
{
foreach(var item in list)
{
try
{
throw new Exception("What now?");
}
finally
{
continue;
}
}
}
catch
{
//do I get hit?
}
}
public static void Goto()
{
foreach(var item in list)
{
try
{
goto pigsfly;
}
finally
{
continue;
}
}
pigsfly:
}
public static object ReturnSomething()
{
foreach(var item in list)
{
try
{
return item;
}
finally
{
continue;
}
}
}
public static void Break()
{
foreach(var item in list)
{
try
{
break;
}
finally
{
continue;
}
}
}
所以在最后,是的,雖然是使用輕微的可能性continue
在控制不被轉移的情況,但情況下一個很好的協議(多數?)涉及異常或return
塊。 語言設計師認為這太含糊了,並且(很可能)無法確保在編譯時僅在未傳輸控制流的情況下使用您的continue
。
通常,在finally
塊中使用continue
並沒有意義。 看看這個:
foreach (var item in list)
{
try
{
throw new Exception();
}
finally{
//doesn't make sense as we are after exception
continue;
}
}
“這不會編譯,我認為這完全有道理”
好吧,我認為不是。
當您字面上有catch(Exception)
則不需要finally(甚至可能不需要continue
)。
當您擁有更現實的catch(SomeException)
,如果未捕獲異常,應該怎么辦? 您continue
想走一種方法,處理另一種異常。
您不能離開finally塊的主體。 這包括break,return和您可能的continue關鍵字。
可以執行finally
塊,但有一個等待重新拋出的異常。 能夠(通過continue
或其他任何方式)退出該塊而不拋出該異常並沒有任何意義。
如果您想繼續循環,無論發生什么情況,都不需要finally語句:只需捕獲異常就不會重新拋出。
finally
運行,無論是否引發未捕獲的異常。 其他人已經解釋了為什么這會continue
不合邏輯,但是這里有一個替代方案,它遵循了此代碼似乎要求的精神。 基本上, finally { continue; }
finally { continue; }
說:
(1)可以通過在每個catch
的末尾放置continue
來滿足,並且(2)可以通過存儲未捕獲的異常以待稍后拋出來滿足。 您可以這樣寫:
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);
}
實際上, finally
在第三種情況下也將執行,在這種情況下,根本不會引發任何異常,無論是捕獲還是未捕獲。 如果需要的話,您當然可以在try-catch塊之后放置一個continue
,而不是在每個catch
。
由於Python 3.8
在finally
塊中continue
,因此允許。
由於實現存在問題,finally子句中的continue語句是非法的。 在Python 3.8中,取消了此限制。 (由Serhiy Storchaka在bpo- 32489中貢獻。)
該語言的設計者根本不想(或無法)推斷由控制傳遞終止的finally塊的語義。
一個問題或可能的關鍵問題是, finally
塊作為某些非本地控制傳輸(異常處理)的一部分而執行。 控制傳遞的目標不是封閉循環; 異常處理將中止循環並繼續展開。
如果我們從finally
清除塊中移出了控制權,則原始控制權被“劫持”。 它被取消,控制權轉移到其他地方。
語義可以解決。 其他語言也有。
C#的設計人員決定簡單地禁止靜態的,類似於“ goto”的控件傳輸,從而在某種程度上簡化了事情。
但是,即使您這樣做,也不能解決如果從finally
啟動動態傳輸會發生什么問題:如果finally塊調用一個函數並且該函數拋出該怎么辦? 然后,原始異常處理被“劫持”。
如果弄清了第二種劫持形式的語義,則沒有理由取消第一種劫持。 它們實際上是同一回事:控件轉移就是控件轉移,無論它是否在相同的詞法范圍內。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.