2015-04-14 16 views
13

接口IDisposable的目的是以有序的方式釋放非託管資源。它與using關鍵字緊密相關,該關鍵字定義了一個範圍,在該範圍之後將討論所涉及的資源。是否濫用IDisposable從「使用」聲明中受益?

由於這種機制非常整齊,我一再試圖讓班級實施IDisposable,以便能夠以非預期的方式濫用此機制。例如,一個可以實現類來處理嵌套的背景是這樣的:

class Context : IDisposable 
{ 
    // Put a new context onto the stack 
    public static void PushContext() { ... } 

    // Remove the topmost context from the stack 
    private static void PopContext() { ... } 

    // Retrieve the topmost context 
    public static Context CurrentContext { get { ... } } 

    // Disposing of a context pops it from the stack 
    public void Dispose() 
    { 
     PopContext(); 
    } 
} 

在調用代碼可能是這樣的用法:

using (Context.PushContext()) 
{ 
    DoContextualStuff(Context.CurrentContext); 
} // <-- the context is popped upon leaving the block 

(請注意,這只是一個例子,而不是到這個問題的主題)

Dispose()在離開聲明範圍時被調用的事實也可以被利用來實現各種依賴於範圍的事情,例如計時器。這也可以通過使用try ... finally結構來處理,但是在那種情況下,程序員將不得不手動調用一些方法(例如Context.Pop),其中using構造可以爲此做。

IDisposable的這種用法並不符合其預期用途as stated in the documentation,但誘惑依然存在。

是否有具體的理由來說明這是一個糟糕的主意,並永遠拋棄我的幻想,例如垃圾回收,異常處理等等的複雜性。或者我應該繼續前進並放縱自己,以這種方式濫用這種語言概念?

+5

有很多其他的概念可能會被濫用,上面是其中的一個,唯一的問題是**可讀性**,請記住您的代碼應該清晰/可讀並且可以由其他開發人員維護。 – Habib

+4

我同意Habib。總是想想這個可憐的混蛋,從現在開始的18個月裏,你將不得不使用你的代碼。有一個很好的機會,混蛋將是你:-) –

+1

這是一個主觀的問題,但你可以注意到,ASP.NET MVC框架濫用IDisposable這種方式 - 例如'FormExtensions.BeginForm' – Joe

回答

10

所以在asp.net MVC的觀點,我們可以看到下面的結構:

using(Html.BeginForm()) 
{ 
    //some form elements 
} 

濫用?微軟說不(間接)。

如果您有需要東西一旦你用它做發生的構建,IDisposable可以經常鍛鍊身體相當不錯。我已經做了不止一次。

+3

與交易範圍類似。 – Magnus

+1

同意支付。它被微軟用於不總是釋放資源的方式,所以我認爲它是「允許的」。這就是說,可讀性應該是你關心的問題。我認爲'BeginForm'很清楚;從列表中彈出,而不是太多。 –

+0

如果'using'行包含「Push」,我會說popping非常明顯。 – Medinoc

3

「是否濫用IDisposable接口來使用它」?大概。

是否使用using作爲純粹的「範圍」構造使更明顯的意圖和更好的代碼可讀性?當然。

後者勝過我,所以我說使用它。

+0

爲什麼不直接使用'try/finally'?它是一樣可讀的。 –

+0

@ChrisDunaway在這種情況下,我不同意,主要是因爲(a)在這種情況下,你最終會得到一個空的'finally'和(b)IMO,因爲'using'聲明範圍意圖比'try/finally '。對我來說,'使用'說:「我正在做這件事的事情,並希望它隨後消失」; 'try/finally'說「我可能在這裏得到一個異常,我想處理它」。 –

+0

我不得不不同意你的陳述的一部分。 「try/finally」(沒有catch子句)並不意味着有關異常的任何信息。終於會有任何必要的清理代碼,並說:「我想要做的後續,然後最終清理」。至少我是這樣讀的。 –

0

你當然不會是第一個以這種方式「濫用」IDisposable的人。可能是我最喜歡使用它是定時器,作爲StatsD.NET client表明:

using StatsdClient; 
... 
using (statsd.LogTiming("site.db.fetchReport")) 
{ 
    // do some work 
} 
// At this point your latency has been sent to the server 

事實上,我敢肯定,微軟自己在一些圖書館使用它。我的經驗法則是 - 如果它提高了可讀性,那就去做吧。

+0

爲什麼不使用'try/finally'?它是一樣可讀的。 –

+0

@ChrisDunaway這裏的要點是在使用塊內對操作進行計時,而不是防止出現異常。你可以把它看作'使用myTimer,做...',並且通過這樣做,將其他三行代碼(timer.Start,timer.Stop,timer.SendToServer)壓縮成更可讀的東西。 – georgevanburgh

相關問題