小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

正確實現(xiàn) IDisposable 接口 - Andrew Xu 的 .NET 技術(shù)隨筆 -...

 xnet 2007-01-17

正確實現(xiàn) IDisposable

 

.NET中用于釋放對象資源的接口是IDisposable,但是這個接口的實現(xiàn)還是比較有講究的,此外還有FinalizeClose兩個函數(shù)。

MSDN建議按照下面的模式實現(xiàn)IDisposable接口:

 1 public class Foo: IDisposable
 2 {
 3     public void Dispose()
 4     {
 5        Dispose(true);
 6        GC.SuppressFinalize(this);
 7     }
 8 
 9     protected virtual void Dispose(bool disposing)
10     {
11        if (!m_disposed)
12        {
13            if (disposing)
14            {
15               // Release managed resources
16            }
17  
18            // Release unmanaged resources
19  
20            m_disposed = true;
21        }
22     }
23  
24     ~Foo()
25     {
26        Dispose(false);
27     }
28  
29     private bool m_disposed;
30 }
31  
32 

 

.NET的對象中實際上有兩個用于釋放資源的函數(shù):DisposeFinalizeFinalize的目的是用于釋放非托管的資源,而Dispose是用于釋放所有資源,包括托管的和非托管的。

 

在這個模式中,void Dispose(bool disposing)函數(shù)通過一個disposing參數(shù)來區(qū)別當前是否是被Dispose()調(diào)用。如果是被Dispose()調(diào)用,那么需要同時釋放托管和非托管的資源。如果是被~Foo()(也就是C#Finalize())調(diào)用了,那么只需要釋放非托管的資源即可。

 

這是因為,Dispose()函數(shù)是被其它代碼顯式調(diào)用并要求釋放資源的,而Finalize是被GC調(diào)用的。在GC調(diào)用的時候Foo所引用的其它托管對象可能還不需要被銷毀,并且即使要銷毀,也會由GC來調(diào)用。因此在Finalize中只需要釋放非托管資源即可。另外一方面,由于在Dispose()中已經(jīng)釋放了托管和非托管的資源,因此在對象被GC回收時再次調(diào)用Finalize是沒有必要的,所以在Dispose()中調(diào)用GC.SuppressFinalize(this)避免重復(fù)調(diào)用Finalize。

 

然而,即使重復(fù)調(diào)用FinalizeDispose也是不存在問題的,因為有變量m_disposed的存在,資源只會被釋放一次,多余的調(diào)用會被忽略過去。

 

因此,上面的模式保證了:

 

1、 Finalize只釋放非托管資源;

2、 Dispose釋放托管和非托管資源;

3、 重復(fù)調(diào)用FinalizeDispose是沒有問題的;

4、 FinalizeDispose共享相同的資源釋放策略,因此他們之間也是沒有沖突的。

 

C#中,這個模式需要顯式地實現(xiàn),其中C#~Foo()函數(shù)代表了Finalize()。而在C++/CLI中,這個模式是自動實現(xiàn)的,C++的類析構(gòu)函數(shù)則是不一樣的。

 

按照C++語義,析構(gòu)函數(shù)在超出作用域,或者delete的時候被調(diào)用。在Managed C++(即.NET 1.1中的托管C++)中,析構(gòu)函數(shù)相當于CLR中的Finalize()方法,在垃圾收集的時候由GC調(diào)用,因此,調(diào)用的時機是不明確的。在.NET 2.0C++/CLI中,析構(gòu)函數(shù)的語義被修改為等價與Dispose()方法,這就隱含了兩件事情:

 

1、 所有的C++/CLI中的CLR類都實現(xiàn)了接口IDisposable,因此在C#中可以用using關(guān)鍵字來訪問這個類的實例。

2、 析構(gòu)函數(shù)不再等價于Finalize()了。

 

對于第一點,這是一件好事,我認為在語義上Dispose()更加接近于C++析構(gòu)函數(shù)。對于第二點,Microsoft進行了一次擴展,做法是引入了“!”函數(shù),如下所示: 

1 public ref class Foo
2 {
3 public:
4        Foo();
5        ~Foo();       // destructor
6        !Foo();       // finalizer
7 };
8 

 

“!”函數(shù)(我實在不知道應(yīng)該怎么稱呼它)取代原來Managed C++中的Finalize()GC調(diào)用。MSDN建議,為了減少代碼的重復(fù),可以寫這樣的代碼: 

 1 ~Foo()
 2 {
 3     //釋放托管的資源
 4     this->!Foo();
 5 }
 6  
 7 !Foo()
 8 {
 9     //釋放非托管的資源
10 }
11 

 

對于上面這個類,實際上C++/CLI生成對應(yīng)的C#代碼是這樣的:

 

 1 public class Foo
 2 {
 3     private void !Foo()
 4     {
 5        // 釋放非托管的資源
 6     }
 7  
 8     private void ~Foo()
 9     {
10        // 釋放托管的資源
11        !Foo();
12     }
13  
14     public Foo() 
15     {
16     }
17  
18     public void Dispose()
19     {
20        Dispose(true);
21        GC.SuppressFinalize(this);
22     }
23  
24     protected virtual void Dispose(bool disposing)
25     {
26        if (disposing)
27        {
28            ~Foo();
29        }
30        else
31        {
32            try
33            {
34               !Foo();
35            }
36            finally
37            {
38               base.Finalize();
39            }
40        }
41     }
42  
43     protected void Finalize()
44     {
45        Dispose(false);
46     }
47 }
48 

 

由于~Foo()!Foo()不會被重復(fù)調(diào)用(至少MS這樣認為),因此在這段代碼中沒有和前面m_disposed相同的變量,但是基本的結(jié)構(gòu)是一樣的。

 

并且,可以看到實際上并不是~Foo()!Foo()就是DisposeFinalize,而是C++/CLI編譯器生成了兩個DisposeFinalize函數(shù),并在合適的時候調(diào)用它們。C++/CLI其實已經(jīng)做了很多工作,但是唯一的一個問題就是依賴于用戶在~Foo()中調(diào)用!Foo()。

 

關(guān)于資源釋放,最后一點需要提的是Close函數(shù)。在語義上它和Dispose很類似,按照MSDN的說法,提供這個函數(shù)是為了讓用戶感覺舒服一點,因為對于某些對象,例如文件,用戶更加習慣調(diào)用Close()

 

然而,畢竟這兩個函數(shù)做的是同一件事情,因此MSDN建議的代碼就是: 


1 public void Close()
2 {
3     Dispose(();
4 }
5 
6 

這里直接調(diào)用不帶參數(shù)的Dispose函數(shù)以獲得和Dispose相同的語義。這樣似乎就圓滿了,但是從另外一方面說,如果同時提供了DisposeClose,會給用戶帶來一些困惑。沒有看到代碼細節(jié)的前提下,很難知道這兩個函數(shù)到底有什么區(qū)別。因此在.NET的代碼設(shè)計規(guī)范中說,這兩個函數(shù)實際上只能讓用戶用一個。因此建議的模式是: 

 1 public class Foo: IDisposable
 2 {
 3     public void Close()
 4     {
 5        Dispose();
 6     }
 7  
 8     void IDisposable.Dispose()
 9     {
10        Dispose(true);
11        GC.SuppressFinalize(this);
12     }
13  
14     protected virtual void Dispose(bool disposing)
15     {
16        // 同前
17     }
18 }
19 

 

這里使用了一個所謂的接口顯式實現(xiàn):void IDisposable.Dispose()。這個顯式實現(xiàn)只能通過接口來訪問,但是不能通過實現(xiàn)類來訪問。因此:

 

1 Foo foo = new Foo();
2 
3 foo.Dispose(); // 錯誤
4 (foo as IDisposable).Dispose(); // 正確
5 

 

這樣做到了兼顧兩者。對于喜歡使用Close的人,可以直接用 foo.Close(),并且他看不到 Dispose()。對于喜歡Dispose的,他可以把類型轉(zhuǎn)換為 IDisposable 來調(diào)用,或者使用using語句。兩者皆大歡喜!

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多