大約一年前吧,在某個技術交流群里出現了這么一個問題,大致上問的是Form在ShowDialog並調用了Close方法並沒有及時釋放,緊跟其后的語句仍然能讀到這個Form的相關屬性,也就是說程序並沒有立即釋放它,測試代碼形如:
Form2 frm2 = new Form2();
if (frm2.ShowDialog() == DialogResult.OK)
MessageBox.Show("Yes");
else
MessageBox.Show("No");
frm2.Close();
string strTest = frm2.strTest;
其中frm2里調用按鈕的事件處理中調用了this.Close和this.DialogResult=DialogResult.OK。
當時工作僅一年,.Net本質論也還看的懵懵懂懂的,對Form的機制並不理解,當時根據對GC的理解,猜測是上下文的引用關系導致了GC沒有及時釋放它,今天,剛剛在群里又有人問了相似的問題,閑暇之余(好吧,我承認是工作時間偷懶了~)用Relector看了Form的相關方法,嘗試理解了下它的機制,發現並不是當初想的那么回事兒,整個Form的機制也不像我們從表面上看的那么簡單,它事實上采用了一種消息的機制來實現的,因為工作時間的關系,這里只重點看了涉及到相關問題的showdialog(IWin32Window)和show(IWin32Window)方法(無參的show方法其實也是調用了這個方法並傳遞了一個null參數),以及它重寫了的Dispose方法,現就當前理解到的進行一個簡單的分析,以留作備忘,待日后再做補足。
首先,先就問題而言,說一下跟問題相關的部分,逆向分析從上述代碼來看就從Form的Close()着手吧~
public void Close()
{
if (base.GetState(0x40000))
{
throw new InvalidOperationException(SR.GetString("ClosingWhileCreatingHandle", new object[] { "Close" }));
}
if (base.IsHandleCreated)
{
this.closeReason = CloseReason.UserClosing;
base.SendMessage(0x10, 0, 0);
}
else
{
base.Dispose();
}
}
//這是base.Dispose方法,而不是Form重寫后的
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
這是Form的Close和base的Dispose方法,Form重寫了那個接收一個bool類型參數的Dispose方法,此方法具體代碼暫且不表,感興趣的可以自己去看下,它簡單的說就是當參數為true時置空釋放一些句柄,如果有父窗體的話,就調用父窗體的RemoveOwnedForm(this)方法來移除父窗體對自身的調用,並將保存父窗體句柄的屬性置空,如果有子窗體的話則循環調用子窗體的Dispose方法釋放他們,再之后則調用base的Dispose(true),最后釋放MainMenu相關的資源;而如果參數為false則直接調用base.Dispose(false),這之后是一層層的自身資源釋放以及父類的Dispose方法的調用,我們可以簡單的理解為Form一旦調用了上一層父類的Dispose則當前窗體就會得到釋放(這里可以理解為告訴了GC和其他調用這些是要釋放的資源,而真正的資源回收是由GC決定的,當然,你也可以主動的調用GC的Collect的方法使其回收這些它已知的要釋放的資源),也就是說只有當IsHandleCreated的值為false,調用Form的Close方法才會使其立即得到“釋放”,而我們在程序中像一開始所說的那樣寫一段簡單的測試代碼並加斷點調式就會發現IsHandleCreated不論是show還是showdialog方法出示窗體,當此窗體調用Close時它的IsHandleCreated都為true,這也就是為什么Form在show以及showdialog之后調用了Close,而窗體並沒有立即得到釋放,它依然可以被訪問的原因,而為什么IsHandleCreated為true以及這個屬性是干毛的,先看一下msdn對Control.IsHandleCreated的解釋(懶得截圖了,直接復制文本):
如果已經為控件分配了句柄,則為 true;否則為 false。
備注
使用 IsHandleCreated 屬性確定是否調用了 CreateHandle。
所以,一開始的問題的根源也就迎刃而解了,至於Form背后對這個屬性的操作,以及由這個問題引發出的關於Form窗體的機制的問題的思考,下次有時間了再做整理,六點下班了,嘿嘿~
PS:歡迎大伙提出個人見解,如果有對這方面理解深刻的童鞋同樣可以回復講下自己的理解,我會在稍候的篇幅中對自己的理解進行闡述同時也對大家的理解進行歸納總結和相關測試~
