2012-06-08 28 views
2

試圖瞭解何時需要執行IDisposable:當所有成員被明確處置時,一個類是否需要實現IDisposable?

我寫了一個小例子。

public class FileManager 
    { 
    private FileStream fileStream; 
    public void OpenFile(string path) 
    { 
     this.fileStream = File.Open(path, FileMode.Open, FileAccess.Read); 
    } 
    public void CloseFile(string path) 
    { 
     if (this.fileStream != null && this.fileStream.CanRead) 
     { 
     this.fileStream.Close();   
     } 
     this.fileStream.Dispose(); 
    } 
    } 

// client 
var manager = new FileManager(); 
manager.Open("path"); 
manager.Close("path"); 

請問這個類必須實現IDisposable因爲它有一個管理資源(的FileStream)持有到一個非託管資源(文件)?或者我不必實施IDisposable,因爲我正在課堂內清理?

困惑。

+0

http://stackoverflow.com/q/1136210/284240 –

+1

當調用'manager.Close'之前拋出異常時會發生什麼? – hvd

+0

如果有疑問,請運行FxCop - 它會檢測並說明Dispose何時何地需要執行。 –

回答

5

對於它實現IDisposable,並可能在一個不平凡的方式這樣做的任何類型的每一個實例,它必須在每現在可以確定該實例將如何成爲Dispose d。在大多數情況下,這意味着每個IDisposable實例將擁有一個明確定義的所有者,它負責調用Dispose。在由該類創建的FileStream實例的情況下,您的類是所有者,因爲沒有其他的將能夠Dispose它。

類,但到IDisposable實例他們自己引用應該幾乎始終貫徹IDisposable,用自己的Dispose方法Dispose他們所擁有的IDisposable對象的字段。你的班級有這樣一個領域;因此它應該執行IDisposable

只要有可能,應該設計一個需要清理的類,以便調用IDisposable.Dispose就足以執行任何和所有可能需要的清理。在某些情況下,不使用其他方法進行清理可能不切實際,但這些情況非常罕見。如果可以設計一個班級,以便Dispose負責所有必要的清理工作,則應該這樣做。

+0

這是我正在尋找的答案類型。 –

+0

@白ジームス:很高興有用。對於那些建議如果類使用其他方法進行清理時,或者如果它們的清理需要通常不與「IDisposable」相關聯的操作,則不應該實現「IDisposable」的人會感到有些厭煩。 「IDisposable」的要點是能夠說:(1)創建一個需要清理的對象的人不應該去研究如何清理它 - 只需調用「IDisposable.Dispose」; (2)在其整個生命週期中擁有「IDisposable」對象的類別通常不必擔心... ... – supercat

+0

@白ジェムム:...當消費者完成它時,如何找出它,因爲創建它的人應該要麼調用'IDisposable.Dispose',要麼將責任交給其他合同指定'IDisposable.Dispose'的對象。當然,有可能在一個實體解除處置責任後,被賦予責任的實體將在不調用「Dispose」的情況下放棄該對象,但如果發生這種情況,則是後一個實體,而不是前者,這被破壞。 – supercat

0

看不到任何real在這裏實現IDisposable的好處,如果不是聲明式的。如果有人看到你的班級實施IDisposable,他明白有些地方的資源必須在使用後清理乾淨。這只是一個內置的.net宣言類型這樣的轉折。

如果你不使用這種模式,你可以自由地做到這一點,但是你違反了建議,主要關注.net類型聲明的社區指南。

+0

我不會實現'IDisposable' * only *,因爲它更容易*使用嵌套'using',但出於我解釋的原因。 – Tigran

1

如果您(或其他開發人員)使用FileManager類並忘記關閉它,您可能需要實現IDisposable。請注意0​​的示例如何在終結器中調用Dispose(false)

1

爲什麼你將路徑傳遞給close方法?就你而言,看起來你的經理可以打開不同的文件,如果他們在打開另一個文件之前關閉,那麼你不會想要處理該對象。

恕我直言,我更願意執行這樣說:

public class FileManager : IDisposable 
{ 
    private string path; 
    private FileStream fileStream; 
    public FileManager(string path) 
    { 
     this.path = path; 
    } 
    public void OpenFile() 
    { 
     this.fileStream = File.Open(path, FileMode.Open, FileAccess.Read); 
    } 
    public void CloseFile() 
    { 
     if (this.fileStream != null && this.fileStream.CanRead) 
     { 
     this.fileStream.Close(); 
     this.fileStream.Dispose(); 
     } 
    } 

    public void Dispose(){ 
     this.CloseFile(); 
    } 
} 

// client 
var manager = new FileManager("path")){ 
manager.OpenFile(); 
//Do other stuff 
manager.CloseFile() 

using(var manager = new FileManager("path")){ 
    manager.OpenFile(); 
    //Do other stuff 
} 
+0

這是我在5分鐘內寫出的一小段樣本,以幫助我解決問題。我不打算使用這個。 –

+0

與往常一樣,答案是「視情況而定」。所以,對於你提供的代碼,這是我的答案。如果你有另一個代碼,我可以幫助你設計,看看是否能夠實現'IDisposable'。這裏沒有黑色和白色。有時候實現'IDisposable'是有意義的,有時它不會。 – ivowiblo

1

在您致電Close法的情況下,你不需要單獨設置。但是,這種情況下的一般做法是實施IDisposable,因爲不能保證該班的消費者會撥打Close

如果創建資源然後將其置於同一方法內,那麼您只能可靠地忽略IDisposable,因爲這是確保資源在使用後絕對處置掉的唯一方法。

1

您應該實施IDisposable。

試想:

var manager = new FileManager(); 
manager.Open("path"); // <- throws for some reason 
manager.Close(); // <- then this never gets called 

當然,你現在可以把這樣一個try /終於在其周圍:

try { 
    var manager = new FileManager(); 
    manager.Open("path"); 
} 
finally { 
    manager.Close(); 
} 

...但是這確實是使用的是什麼和IDisposable接口已經被髮明瞭,使用它可以舒適的寫:

using (var manager = new Manager()) { 
    manager.OpenFile("path"); 
} // and CloseFile will automagically be called here. 
+0

+1這不是我用示例代碼來處理假設情景的意圖,但仍然是好點。 –

+0

@白ジームス錯誤處理完全是關於假設的情況..你總是必須假定,在打開資源的同時或之後的某個時刻,可能會拋出異常,並且必須爲用戶提供一種方式來優雅地處理它。你可以「讓他」用try/finally來做,或者讓他通過實現IDisposable來使用「使用」。人們會感謝你。 :) – stmax

+0

我想我想說這是示例代碼,只用於幫助說明我的問題。在示例代碼中,.Close被調用,並且沒有例外:)。 –

相關問題