[英]C# how to implement Dispose method
我需要一些關於Dispose
方法實現的建議。
在我們的應用程序中,用戶設計自己的UI。 我有一個預覽窗口,顯示UI的外觀。 在此UI中繪制的所有對象最終都來自公共基類ScreenObject。 我的預覽管理器包含對ScreenGrid的單個對象引用,ScreenGrid是整個預覽區域的網格對象。
問題#1
我的一些派生屏幕類保留在非托管資源上,例如數據庫連接,位圖圖像和WebBrowser
控件。 這些類需要處理這些對象。 我在基本ScreenObject
基類中創建了一個虛擬Dispose
方法,然后在每個保存到非托管資源的派生類中實現了一個覆蓋Dispose
方法。 但是,現在我剛剛創建了一個名為Dispose
的方法,我沒有實現IDisposable
。 我應該實現IDisposable
嗎? 如果是這樣,我該如何實現它?
將虛擬Dispose
方法放在沒有非托管資源的基類中是否錯誤,以便您可以利用多態?
問題2
在閱讀Dispose
方法和IDisposable
接口時,Microsoft聲明處置對象應該只為其父級調用Dispose
方法。 父母將為其父母調用它,依此類推。 對我而言,這似乎是倒退。 我可能想要處理一個孩子但保留其父母。
我認為它應該是另一種方式,處置的對象應該處理它的孩子。 然后孩子們應該處理他們的孩子等等。
我錯在這里還是我錯過了什么?
問題1:使用以下模式實現IDisposable
:
public class MyClass : IDisposable
{
bool disposed;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
//dispose managed resources
}
}
//dispose unmanaged resources
disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
問題2:Microsoft的含義是派生類在其父類上調用dispose。 實例的所有者僅在最派生類型上調用Dispose。
一個(縮短的)例子:
class Parent : IDisposable
{
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
//dispose managed resources
}
}
//dispose unmanaged resources
disposed = true;
}
}
class Child : Parent, IDisposable
{
protected override void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
//dispose managed resources
}
base.Dispose(disposing);
}
//dispose unmanaged resources
disposed = true;
}
}
class Owner:IDisposable
{
Child child = new Child();
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
if(child!=null)
{
child.Dispose();
}
}
}
//dispose unmanaged ressources
disposed = true;
}
}
所有者只調用Child上的Dispose
,但不調用Parent。 Child負責在Parent上調用Dispose
。
根據您列出的對象類型(即數據庫,WebBrowser,位圖等),就.NET而言,這些只是受管資源。 因此,您應該在具有一次性類型作為成員的任何類上實現IDisposable
。 如果它們是本地聲明的實例,則只需對它們調用'using()'。 雖然你提到的這些實例確實有非托管資源,但是這些實際上是通過.NET從你使用的類型中抽象出來的。 由於您只使用托管類型,因此您應該實現IDisposable
但不使用終結器 。 如果您真的擁有非托管資源作為類成員,則只需要實現終結器。
看來你將繼承(是a)與聚合/包含混淆(有一個)。 例如,如果“Container”包含一次性資源作為類成員,則稱為聚合/包含。 因此,在Container的IDisposable
實現中調用base.Dispose()
與在Container 內部處理一次性資源無關。 您應該記住,如果一個類派生自Container,比如說“DerivedContainer”,那么它是 Container的一個實例,盡管有其他成員和/或功能。 因此,“DerivedContainer”的任何實例都具有其基類“Container”所具有的所有成員。 如果你從未調用過base.Dispose()
,那么“容器”中的可支配資源將無法正常釋放(它實際上是由GC實現的,但是由於很多原因,只是'讓.NET處理它'是不好的做法) -請參閱我發布的答案, 依賴.NET自動垃圾收集器是不好的做法? 。
如果你沒有調用基類Dispose()
,你最終會得到一個部分處理的對象(放置在派生類中但不在基類中) - 這是一個非常糟糕的場景。 因此調用基類Dispose()
非常重要。
作為一個例子,我在我的博客上寫了一個我已經開發的最佳實踐模式(有很多經驗和調試內存轉儲)。 它展示了如何在基類和派生類上實現IDisposable
:
http://dave-black.blogspot.com/2011/03/how-do-you-properly-implement.html
我實現了IDisposable
class ConnectionConfiguration:IDisposable
{
private static volatile IConnection _rbMqconnection;
private static readonly object ConnectionLock = new object();
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing)
{
return;
}
if (_rbMqconnection == null)
{
return;
}
lock (ConnectionLock)
{
if (_rbMqconnection == null)
{
return;
}
_rbMqconnection?.Dispose();//double check
_rbMqconnection = null;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.