2011-03-04 42 views
9

有人請向我解釋爲什麼下面顯示的代碼在C#中有效,並執行Console.WriteLine的調用?爲什麼在C#中使用(null)有效的情況?

using (null) 
{ 
    Console.WriteLine ("something is here") 
} 

它編譯成(finally塊顯示)。正如你所看到的,編譯器決定不執行Dispose()方法並跳轉到endfinally指令。

IL_0013: ldnull 
IL_0014: ceq 
IL_0016: stloc.1 
IL_0017: ldloc.1 
IL_0018: brtrue.s IL_0021 // branches here and decide not to execute Dispose() 
IL_001a: ldnull 
IL_001b: callvirt instance void [mscorlib]System.IDisposable::Dispose() 
IL_0020: nop 
IL_0021: endfinally 

但是,如果我運行下面的代碼,它將失敗,一個NullReferenceException(預計):

((IDisposable)null).Dispose(); 
IL_0023: ldnull 
IL_0024: callvirt instance void [mscorlib]System.IDisposable::Dispose() 

爲什麼第一個版本編譯?爲什麼編譯器決定不執行Dispose()?在編譯器可能決定不調用using塊中的Dispose()時是否還有其他情況?

+7

嗯...我現在非常懷疑這個帖子的,因爲Eric的最近的博客......這真的是一個真正的問題嗎? – 2011-03-04 08:44:05

+0

這不是已經問過嗎? http://stackoverflow.com/questions/2522822/c-using-statement-with-a-null-object – 2011-03-04 08:49:17

+0

是的,它似乎對我有所臆造。 – 2011-03-04 09:09:04

回答

11

語言規範明確規定(8.13)所拍攝的值是爲空,如果必要的測試,即finally基本上是(與周圍的非可空類型警告)

if(tmp != null) tmp.Dispose(); 

我經常用這個來我優勢,因爲可能爲空,但當它們不是時:需要配置。其實,這裏有一個有用的方案(手動列舉IEnumerable):

IEnumerable blah = ...; // note non-generic version 
IEnumerator iter = blah.GetEnumerator(); 
using(iter as IDisposable) 
{ 
    // loop 
} 

IEnumerator非通用版本不一定IDisposable,但是當它是應該被配置。

+0

感謝您使用*作爲IDisposable *的不錯技巧。正是我在找什麼。 – 2011-03-04 08:45:04

+0

這很聰明,我喜歡。 – Travis 2012-02-24 21:19:57

+0

這對我的口味來說太聰明:) – mafu 2012-04-05 15:48:03

1

我認爲這是using(some_expression)更常見的情況的自然結果,其中some_expressionis allowed to evaluate to null

它將需要一個特殊的規則來區分這種情況和更一般的情況。

0
+0

它在你鏈接的文檔中說了些什麼?在該頁面上搜索'null'返回0個匹配。 – 2011-03-04 08:46:15

+0

在備註部分。 if(font1!= null) ((IDisposable)font1).Dispose(); – Anuraj 2011-03-04 08:48:42

+0

>使用說明被翻譯成三部分:採集,使用和處理。資源的使用被隱式包含在包含finally子句的try語句中。這最後的條款處理資源。如果獲取了空資源,則不會調用Dispose,也不會拋出異常。 https://msdn.microsoft.com/en-us/library/aa664736(v=vs.71).aspx – boro 2015-12-01 14:40:14

相關問題