嗯,我挖了一點在這個問題上,這裏是我的非常個人化結論:
千萬不要使用「throw」,但總是重新拋出一個新的異常,並指定 原因。
這裏是我的推理:
我被我以前與Java經驗的影響和預期的C#拋非常相似的Java。嗯,我挖了一點在這個問題上,這裏是我的意見:
static void Main(string[] args){
try {
try {
throw new Exception("test"); // 13
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
throw ex;// 17
}
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}
產量:
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 17
直觀地說,一個Java程序員本來期望這兩個例外是相同的:
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
但是C#文檔清楚地表明這是預期的:
如果一個異常被指定在throw語句中的異常重新拋出,堆棧跟蹤在當前方法重新啓動,並拋出異常和當前的方法失去了原有的方法之間的調用列表的方式。要保持原始堆棧跟蹤信息的例外情況,請使用throw語句,而不指定異常。「
現在,如果我稍微更改了測試(替換throw ex;通過throw;在第17行)。
try {
try {
throw new Exception("test"); // 13
}
catch (Exception ex) {
Console.WriteLine(ex.ToString());
throw;// 17
}
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
產量:
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 17
顯然,這不是我所期望的(因爲這是原來的問題)。我在第二個堆棧跟蹤中丟失了原始的丟棄點。西蒙懷特黑德將解釋說明了這一點,只有當前方法中沒有發生異常時才保留堆棧跟蹤。所以在同樣的方法中「拋出」沒有參數是非常沒用的,因爲一般來說,它不會幫助你找到異常的原因。
throw new Exception("rethrow", ex);// 17
產量:
做什麼任何Java程序員會做,我換成17行的聲明
System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
System.Exception: rethrow ---> System.Exception: test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13
--- End of inner exception stack trace ---
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 17
這是一個更好的結果。
然後,我開始用方法調用進行測試。
private static void throwIt() {
throw new Exception("Test"); // 10
}
private static void rethrow(){
try{
throwIt(); // 15
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
throw; // 18
}
}
static void Main(string[] args){
try{
rethrow(); // 24
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}
同樣,堆棧跟蹤不是我(Java程序員)所期望的。在Java中,這兩個堆棧都是相同的,並且深度爲三種:
java.lang.Exception: Test
at com.example.Test.throwIt(Test.java:10)
at com.example.Test.rethrow(Test.java:15)
at com.example.Test.main(Test.java:24)
第一個堆棧跟蹤只有兩個方法深。
System.Exception: Test
at ConsoleApplication1.Program.throwIt() in Program.cs:line 10
at ConsoleApplication1.Program.rethrow() in Program.cs:line 15
這就好像是堆棧跟蹤被填充爲堆棧展開過程的一部分。如果我要記錄堆棧跟蹤以調查此時的異常情況,我可能會丟失重要信息。
第二個堆棧跟蹤是三個深度方法,但是第18行(throw;)出現在其中。
System.Exception: Test
at ConsoleApplication1.Program.throwIt() in Program.cs:line 10
at ConsoleApplication1.Program.rethrow() in Program.cs:line 18
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 24
這一觀察類似於剛纔的一個:不保存當前方法範圍堆棧跟蹤,並再次我鬆,其中所述異常發生時調用的方法。例如,如果rethow被寫成:
private static void rethrow(){
try{
if (test)
throwIt(); // 15
else
throwIt(); // 17
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
throw; // 20
}
}
息率
System.Exception: Test
at ConsoleApplication1.Program.throwIt() in Program.cs:line 10
at ConsoleApplication1.Program.rethrow() in Program.cs:line 20
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 26
()拋出異常哪個打電話throwIt? Stack說第20行,15行或17行也是如此?
的解決方案是一樣的前面:包裝事業在新的異常,其產生:
System.Exception: rethrow ---> System.Exception: Test
at ConsoleApplication1.Program.throwIt() in Program.cs:line 10
at ConsoleApplication1.Program.rethrow(Boolean test) in Program.cs:line 17
--- End of inner exception stack trace ---
at ConsoleApplication1.Program.rethrow(Boolean test) in Program.cs:line 20
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 26
我簡單的總結,這一切是永遠不會使用「拋」;但始終重新拋出新例外與指定的原因。
是的,再次閱讀聲明。保持堆棧跟蹤做'扔'不'拋出EX2' –
民俗,請閱讀實際的代碼。在一種情況下,OP使用「throw」,而在另一種情況下,他們使用「throw ex」。然而,在所有*三個例子中(不僅僅是'throw ex'的情況),有三種不同的堆棧(據推測)。如果堆棧軌跡真的不同,那麼這確實是一個有趣的問題。 – siride
@mitch如果你閱讀這個問題,文檔所說的和我觀察到的是不同的!這是我想澄清的。爲什麼ex1和ex2疊加不同,如果我用「throw」重新拋出? – cquezel