18.实现标准的Dispose模式
首先來看MSDN中關于這個接口的說明:
[ComVisible(true)]
public interface IDisposable
{ // Methods
void Dispose();
}
?
1.[ComVisible(true)]:
指示該托管類型對 COM 是可見的.
2.此接口的主要用途是釋放非托管資源。
當不再使用托管對象時,垃圾回收器會自動釋放分配給該對象的內存。但無法預測進行垃圾回收的時間。另外,垃圾回收器對窗口句柄或打開的文件和流等非托管資源一無所知。將此接口的Dispose方法與垃圾回收器一起使用來顯式釋放非托管資源。當不再需要對象時,對象的使用者可以調用此方法。
一:基本應用
1.我們來定義一個實現了IDisposable接口的類,代碼如下:
public class CaryClass :IDisposable
{
public void DoSomething()
{
Console.WriteLine("Do some thing....");
}
?
public void Dispose()
{
Console.WriteLine("及時釋放資源");
}
}
?
2.我們有兩種方式來調用:
2.1.第一種方式,使用Using語句會自動調用Dispose方法,代碼如下:
using (CaryClass caryClass = new CaryClass())
{
caryClass.DoSomething();
}
?
2.2第二種方式,現實調用該接口的Dispose方法,代碼如下:
CaryClass caryClass = new CaryClass();
try {
caryClass.DoSomething();
}
finally
{
IDisposable disposable = caryClass as IDisposable;
if (disposable != null)
disposable.Dispose();
}
兩種方式的執行結果是一樣的。
?
2.3.使用try/finally 塊比使用 using 塊的好處是即使using中的代碼引發異常,CaryClass的Dispose方法仍有機會清理該對象。所以從這里看還是使用try/catch好一些。
二:Disposable 模式
1.在.NET種由于當對象變為不可訪問后將自動調用Finalize方法,所以我們手動調用IDisposable接口的Dispose方法和對象終結器調用的方法極其類似,我們最好將他們放到一起來處理。
?
我們首先想到的是重寫Finalize方法,如下:
protected override void Finalize()
{
Console.WritleLine("析構函數執行...");
}
當我們編譯這段代碼的時候,我們發現編譯器會報如下的錯誤: 這是因為編譯器徹底屏蔽了父類的Finalize方法,編譯器提示我們如果要重寫Finalize方法我們要提供一個析構函數來代替,下面我們就提供一個析構函數:
~CaryClass() { Console.WriteLine("析構函數執行..."); }
?
實際上這個析構函數編譯器會將其轉變為如下代碼:
protected override void Finalize()
{
try {
Console.WritleLine("析構函數執行...");
}
finally {
base.Finalize();
}
}
?
2.然后我們就可以將Dispose方法的調用和對象的終結器放在一起來處理,如下:
public class CaryClass: IDisposable
{
~CaryClass()
{
Dispose();
}
public void Dispose()
{ // 清理資源
}
}
?
3.上面實現方式實際上調用了Dispose方法和Finalize方法,這樣就有可能導致做重復的清理工作,所以就有了下面經典Disposable 模式:
private bool IsDisposed=false;
public void Dispose()
{ Dispose(true);
GC.SupressFinalize(this);
}
protected void Dispose(bool Diposing)
{
if(!IsDisposed)
{
if(Disposing)
{ //清理托管資源
}
//清理非托管資源
}
IsDisposed=true;
}
~CaryClass()
{
Dispose(false);
}
3.1. SupressFinalize方法以防止垃圾回收器對不需要終止的對象調用 Object.Finalize()。
3.2. 使用IDisposable.Dispose 方法,用戶可以在可將對象作為垃圾回收之前隨時釋放資源。如果調用了 IDisposable.Dispose 方法,此方法會釋放對象的資源。這樣,就沒有必要進行終止。IDisposable.Dispose 應調用 GC.SuppressFinalize 以使垃圾回收器不調用對象的終結器。
3.3.我們不希望Dispose(bool Diposing)方法被外部調用,所以他的訪問級別為protected 。如果Diposing為true則釋放托管資源和非托管資源,如果 Diposing等于false則該方法已由運行庫從終結器內部調用,并且只能釋放非托管資源。
3.4.如果在對象被釋放后調用其他方法,則可能會引發 ObjectDisposedException。
?
三:實例解析
1.下面代碼對Dispose方法做了封裝,說明如何在使用托管和本機資源的類中實現 Dispose(bool) 的常規示例:
public class BaseResource : IDisposable
{
// 非托管資源
private IntPtr handle;
//托管資源
private Component Components;
// Dispose是否被調用
private bool disposed = false;
?
public BaseResource() { }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
// 釋放托管資源
Components.Dispose();
}
// 釋放非托管資源,如果disposing為false, 只有非托管資源被釋放
CloseHandle(handle);
handle = IntPtr.Zero;
// 注意這里不是線程安全的
}
disposed = true;
}
// 析構函數只會在我們沒有直接調用Dispose方法的時候調用
// 派生類中不用在次提供析構函數
~BaseResource() { Dispose(false); }
// 如果你已經調用了Dispose方法后再調用其他方法會拋出ObjectDisposedException
public void DoSomething()
{
if (this.disposed)
{
throw new ObjectDisposedException();
}
}
}
public class MyResourceWrapper : BaseResource {
// 托管資源
private ManagedResource addedManaged;
// 非托管資源
private NativeResource addedNative;
private bool disposed = false;
public MyResourceWrapper() { }
protected override void Dispose(bool disposing)
{
if (!this.disposed)
{ try
{
if (disposing)
{
addedManaged.Dispose();
}
CloseHandle(addedNative);
this.disposed = true;
}
finally
{
base.Dispose(disposing);
}
}
}
}
轉載于:https://www.cnblogs.com/movemoon/archive/2012/10/25/2738256.html
總結
以上是生活随笔為你收集整理的18.实现标准的Dispose模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设置3d rotationY 旋转之后元
- 下一篇: ViewVC 1.1.16 发布,CVS