2011-04-13 72 views
35

什麼是對.NET異常捕獲意外地空

會的解釋,我有一個很奇怪的問題,即捕捉到的異常是空見下文。

該代碼使用MEF並努力報告組合錯誤。使用調試器,我可以看到拋出的異常(一個InvalidOperationException),但是當它被下面代碼中的最後一個catch塊捕獲時,ex變量爲null。在調試器和正常執行代碼時都是如此。

static T ResolveWithErrorHandling<T>() where T : class 
{ 
    try 
    { 
     IocContainer.Compose(Settings.Default.IocConfiguration); 
     return IocContainer.Resolve<T>(); 
    } 
    catch (ReflectionTypeLoadException ex) 
    { 
     // ... special error reporting for ReflectionTypeLoadException 
    } 
    catch (Exception ex) 
    { 
     // ex is null - that should not be possible! 
     // ... general error reporting for other exception types 
    } 
    return null; 
} 

我用註釋代替的代碼是非常簡單的代碼來格式化錯誤消息。沒有什麼奇怪的。

我試圖修改代碼以發現可能有什麼樣的影響:

  • 如果我刪除了第一個catch塊(ReflectionTypeLoadException)夾在最終catch塊異常不再爲空。
  • 如果我在第一個catch塊中捕獲到另一個異常類型,則在最終catch塊中捕獲的異常不再爲空。
  • 如果我爲InvalidOperationException添加一個catch塊作爲第一個catch塊,那麼在該塊中捕獲的異常不爲null。
  • 如果我在兩個catch塊之間爲InvalidOperationException添加一個catch塊,那麼在該塊中捕獲的異常爲null。

該項目使用Code Contracts並且編譯器生成的代碼被後處理以檢查合同。不幸的是,我還沒有想出一種方法來擺脫這個測試的目的,而無需對項目進行大手術。

我目前的解決方法是不捕獲ReflectionTypeLoadException,而是在一般異常處理程序中分支ex類型。

對這種「不可能」的行爲有什麼解釋?什麼是ReflectionTypeLoadException catch塊?


令人尷尬的是,該異常不爲空,並且它不能爲null,符合C#標準15.9.5。

但是,在項目can mess up the display of local variables in the debugger中使用代碼契約,因爲編譯器生成的IL代碼可以由代碼契約重寫,因此最終的IL與調試信息略有不同步。在我的情況下,ex變量顯示爲空,即使它不是。在應用程序終止之前發生的錯誤報告的不幸本質意味着我相信錯誤報告不會因爲ex爲空而被調用,並且ex.Message會在我的catch塊中拋出NullReferenceException。使用調試器,我能夠「驗證」ex爲空,除非它實際上不爲空。

我的混淆因爲ReflectionTypeLoadException的catch塊似乎影響調試器顯示問題而變得更加複雜。

感謝所有回覆。

+0

實際上是否有拋出的'ReflectionTypeLoadException'在任何地方? – Jaymz 2011-04-13 14:30:53

+1

只是一個筆記,但你可以處理不同類型的異常,或者你只是報告相同的每個?如果這是通用報告,並且您無法處理異常,那麼我不確定您是否需要對捕獲進行範圍調整。 – 2011-04-13 14:35:38

+0

當您爲InvalidOperationExecption添加捕獲時會發生什麼? – 2011-04-13 14:37:03

回答

11

剛剛遇到了同樣的問題。我終於發現,我用同樣的名字找到了不同的例外情況,就像你做的那樣:

catch (ReflectionTypeLoadException ex) 
{ 
    // ... 
} 
catch (Exception ex) 
{ 
    // ex is not null! 
    // ... 
} 

兩者都被命名爲'ex'。改變這兩個名字之一爲我解決了這個問題,如:

catch (ReflectionTypeLoadException reflectionEx) 
{ 
    // ... 
} 
catch (Exception ex) 
{ 
    // ex is null - that should not be possible! 
    // ... 
} 
4

你應該檢查一下,如果IocContainer在Exception ex中檢測到ex.InnerException而不檢查它是否爲空。

C#高興地接受throw null,最終以catch (Exception)結束。

+4

如果拋出一個空異常(例如,如果'ex.InnerException'爲空),則會拋出'NullReferenceException'。在C#中,捕獲的異常永遠不能爲空。除了在我的情況... – 2011-04-13 14:56:27

+0

啊,我的壞,我只是有一種預感,建立了一個測試用例,盤旋在「ex」變量上,看到「引用沒有設置爲一個實例」,錯誤地認爲它是一個真實的空值。 – 2011-04-13 21:24:59

0

我也有同樣的情況。它恰好是Eclipse調試器的一個缺陷。 (真的,這種情況可能只是一些調試器錯誤的結果)。

Eclipse重新啓動就足夠了 - 運行時異常變得正常,不爲空。其他調試器可能不那麼友好。

4

我遇到了同樣的問題。即使正在捕獲正確類型的異常(UpdateException),在調試器中查看該異常也是null。我可以通過打開例外助手來查看例外情況。

只要我關閉「執行運行時合同檢查」,就會捕獲不再爲空的異常。我一直在積極地使用代碼合同進行爲期一年的工作,並且在我最近在這個特定項目中開始使用EF 4.1之前沒有看到過這個問題 - 但是我不知道EF是否是一個控制變量, 。

5

我跑了同樣的問題。在我的情況下,重命名異常變量(例如ex => ex1)允許我捕捉任何異常...

1

異常事實上不是null,這是調試器的問題。 代碼契約(ccrewrite)更改IL操作碼並擾亂調試器,因爲leave.s操作碼轉換爲離開操作碼。 這兩個操作碼具有不同的大小和指令地址更改,這就是爲什麼當異常名稱相同時調試器會丟失。

您可以在調試器中使用$ exception來解決該問題。