第一件事當然是要記得實作Dispose方法,第二件事情是要讓Dispose方法可以被重複引用。
Example:
建立一個CSampleClass類別如下
建立一個CSampleClass類別如下
class CSampleClass
: IDisposable
{
public
String Name { get;
set; }
public
Dictionary<String,
String> ownedCar;
/// <summary>
/// 建構
/// </summary>
public
CSampleClass()
{
ownedCar = new Dictionary<string, string>();
}
/// <summary>
/// 解構
/// </summary>
~CSampleClass()
{
DoDispseStep();
}
/// <summary>
/// Dispose
/// </summary>
public
void Dispose()
{
DoDispseStep();
}
/// <summary>
/// Dispose 的步驟
/// </summary>
private
void DoDispseStep()
{
Name = "";
Console.WriteLine("移除 ownedCar {0} 筆資料", ownedCar.Count);
ownedCar = null;
}
}
|
主程式
using (CSampleClass
sample = new CSampleClass())
{
sample.Name = "JB";
sample.ownedCar.Add("FOCUS 1.6", "2012"
);
sample.ownedCar.Add("MAZDA 1.6", "2005"
);
var cars = from x
in sample.ownedCar.AsQueryable()
select new
{ Name = x.Key , Year = x.Value };
foreach(var
item in cars){
Console.Write("車種 {0},年份 {1}\n", item.Name, item.Year);
}
}
|
看起來不但實作了Dispose方法,連解構方法我們都加入了。
眼尖的朋友應該已經看到問題了,在DoDispseStep()方法中,這一行程式碼會有問題
Console.WriteLine("移除 ownedCar {0} 筆資料", ownedCar.Count);
Console.WriteLine("移除 ownedCar {0} 筆資料", ownedCar.Count);
實際執行程式後,USING此物件結束後會去Call
Dispose()方法,此時Dictionary物件ownedCar仍有值,所以這一行還不會有問題。 但是關閉程式時,GC機制會再去Call物件的Finalizer(解構方法),這時候ownedCar時候已經沒有參考任何值了,所以就會Error。
所以要做到「讓Dispose方法可以被重複引用」,可以…
ü 判斷物件是否需要Dispose
例如上面的DoDispseStep程式碼可改為
例如上面的DoDispseStep程式碼可改為
if (ownedCar != null
&& ownedCar.Count > 0)
{ Console.WriteLine("移除 ownedCar {0} 筆資料", ownedCar.Count); ownedCar = null; } |
ü
設定一個Dispose Flag判斷是否已經做過Dispose
在類別裡面放一個是否做過Dispose的註記:
在類別裡面放一個是否做過Dispose的註記:
private bool DisposedFlag = false;
|
DoDispseStep程式碼改為先判斷此註記 …
if (DisposedFlag == false)
{ Name = ""; Console.WriteLine("移除 ownedCar {0} 筆資料", ownedCar.Count); ownedCar = null; DisposedFlag = true; } |
ü
在Dispose後加上
GC.SupperessFinalize(物件),告訴CLR此物件已正確清除,不必再到Finalizer(解構)
public void
Dispose()
{
DoDispseStep();
GC.SuppressFinalize(this);
}
|
關於GC.SupperessFinalize的用法時機可參考此文 :
沒有留言:
張貼留言