2015-11-04 60 views
4

我在瀏覽.NET Framework的源代碼,試圖瞭解其他的問題,我看到這個代碼(PeerNearMe.csSystem.Net.PeerToPeer.Collaboration):設置字段值終於{}

private bool m_Disposed; 

protected override void Dispose(bool disposing) 
{ 
    if (!m_Disposed){ 
     try{ 
      m_Disposed = true; 
     } 
     finally{ 
      base.Dispose(disposing); 
     } 
    } 
} 

是否有任何理由將變量賦值放在try區塊中?可能會以例外的方式失敗嗎?起初,我認爲這是因爲即使線程被終止,最終也會被執行:Thread.Abort()

未完成的finally塊在線程被中止之前執行。

在這種情況下我期望 try塊包括所有方法中:

try { 
    if (!m_disposed) 
     m_disposed = true; 
} 
finally { 
    base.Dispose(disposing) 
} 

然而they也說:

調用中止可能會阻止如果線程正在中止的線程位於代碼的受保護區域中,例如catch塊,finally塊或約束執行區。如果調用Abort的線程持有中止線程所需的鎖定,則會發生死鎖。

IMO調用基類的虛擬方法是點點在這種情況下跳躍在黑暗

總之:該代碼的這一點是什麼?它真的試圖實現什麼?如果是因爲Thread.Abort()那麼是不是錯了

編輯:如果它真的Thread.Abort()只是因爲那麼如果if (!m_Disposed) {之後,但之前try {發生中止它不會做其工作。請注意,Dispose()必須對多個呼叫具有彈性,並且無需執行任何操作(無論何時調用)。

+0

反諷 - MSDN建議避免_和領域,他們匈牙利命名法已經在內部完成了。 – niksofteng

+0

@dotnetkid,轉換隻是轉換。只要整個組織遵循它,它就可以工作。 – qxg

+0

也可能是這種情況,此代碼的以前版本在'm_disposed = true;'語句之前有更多語句。而try/finally塊只是一個剩餘的。 –

回答

4

唯一可能發生的是異步異常 - Thread.Abort就是一個例子,但也有Thread.InterruptOutOfMemoryException之類的東西。

你的建議實際上打破了代碼,因爲你打電話base.Dispose,無論實例是否已經處置 - 這不是意圖。

現在,Thread.Abort應該只在終止一個應用程序域時使用 - 所以你不在乎m_disposed = true是否成功,該域即將被拆除。但是,您仍然關心釋放任何本地資源,因爲這些資源通常與進程綁定,而不是應用程序域(有時甚至超越進程或整個機器)。

finally中的代碼有機會運行,即使在Thread.Abort的中間 - 沒有其他方法可以確保代碼在異步異常期間運行。通過在finally子句中調用base.Dispose,您確保它至少有機會執行,並且在操作過程中不會終止(但請注意,執行的所有finally子句都有固定的時間限制 - 您不想在finally中做任何複雜的事情)。

現在,在這種特殊情況下,沒有真正的理由這樣做 - 基類也沒有做任何事情。所以它可能只是團隊使用的一種常見的Dispose模式:)由於Dispose專爲本地資源的確定性發布而設計,因此在finally子句中稱其爲絕對安全 - 它不應該做任何工作,只是釋放本地資源。當然,Dispose經常被濫用 - 但你只是收穫你播下的東西。

最後,不要忘了,這也正是一個using條款做了什麼,所以如果你使用using,你已經在finally條款運行Dispose方法!

using (var bmp = new Bitmap()) 
{ 
    ... 
} 

被翻譯成的

Bitmap bmp = null; 
try 
{ 
    bmp = new Bitmap(); 

    ... 
} 
finally 
{ 
    if (bmp != null) bmp.Dispose(); 
} 

總而言之等同,沒有什麼可疑的有關實現的,真的:)

+0

我同意你的一切,但是_「...打破了代碼,因爲......這不是這個意圖。」我的意思是:Dispose()必須對多個調用有彈性。如果中止發生在if(...)之後但在嘗試之前{那麼基類將不會被調用。 –

+0

@AdrianoRepetti事情是,它真的沒什麼關係。你應該總是*在某個層次上調用'finally'塊中的'Dispose' - 這是它的全部目的。這種編寫'Dispose'方法本身的方式確保在'finally'內調用基類的Dispose方法 - 這不是一個壞主意,因爲你不應該依賴基類的實現細節。 – Luaan

0

我不確定爲什麼它在試一試,因爲它只是分配一個變量,也許別人可以告訴我們這個。

我想說,你的期望會採取不同的行爲。將整個嘗試最終放入if(!m_disposed)中意味着如果該m_disposed爲true,則該對象不會調用Dispose,而您的期望將調用dispose而不管m_disposed值。

+1

這是真的,但您應該可以多次調用Dispose()而沒有任何副作用,並且如果線程在if(!m_disposed)之後中止(但在m_disposed = true之前),它也會調用base.Dispose()。 –

+1

@AdrianoRepetti當你卸載一個應用程序域時,許多這些保證不再適用 - 而且這是唯一應該使用'Thread.Abort'的地方。 – Luaan

+0

@Luaan我不這麼認爲,否則這不是保證!如果這是該代碼的目的(防止異步異常),那麼它可能簡單地失敗。 –