Cannot access a disposed object.問題根源所在.....

pamxy發表於2013-10-05

轉自:http://xdeduzb.blog.163.com/blog/static/819936372010417557105/http://

帶有UI的C#程式在初始化介面或者由使用者觸發某一UI更新的時候常常會遇到這樣的JIT異常:

System.ObjectDisposedException: Cannot access a disposed object.

Object name: 'XXXX'.

從字面上理解,就是無法得到一個已經被終止的物件。那麼在什麼情況下這樣的事情會發生呢?

看一段程式碼就能夠理解了。

 


Code
           public AuthenticationForm()
            {
                // Required for Windows Form Designer support

                InitializeComponent();

                // TODO: Add any constructor code after InitializeComponent call

                this.action = FormAction.View;

                AppButtons.AppParent = this;

                this.EDITCTLS = new Control[] {RoleDGrid, RegionDGrid, UserNameTBox, CheckAllButton, ClearAllButton, ActiveCkBox, RoleCheckAllButton, RoleClearAllButton};

                this.Initialization();
                BeginAuth("GetUser", new object[]{AddUserButton});

            }


Main方法執行了MainForm的初始化,完成必要元件例項化和資料匯入,開始等待使用者輸入。

Ok,使用者這時候點選了一個登入選單,以上form constructor程式碼經事件觸發,開始執行,啪啪啪完成新form的初始化,最後一步看到BeginAuth方法,它要完成對使用者的驗證,如果驗證通過,登入Form要顯示,如果驗證失敗,主程式要返回錯誤資訊,終止此form的所有資源。

但請注意,這個BeginAuth可不能隨便寫寫。看看這段BeginAuth的實現吧:

     

 

 DataManager.SendAsyncWSRequest(this, this.displayDelegate, spName, DataManager.XMLDOC.InnerXml, hash);
DataManager是資料底層傳輸處理的介面,它是通用的。DataManager要發出WebService的資料請求,然後獲得回答(response),再通過this傳入的CallingForm例項呼叫Form的另一個方法EndAuth。

callingForm.EndAuth(resultXML, spName, hash, new ResponseArgs(false, errorNode.InnerXml, AsyncFailType.WSCaught));
EndAuth要解析WebService的response,判斷是否驗證通過,和相應Form的資源如何響應。以下是簡單的EndAuth實現:

 

Code
         if(resp.Success == false)
          {
                MessageBox.Show(re.Msg, spName + ": WebService call fails");

                base.EndAuth(re.Msg, spName, hash, re);

                this.Close();

                return;

           }

           else

                UpdateDisplay();


Form在失敗驗證之後會被馬上close掉,換句話說,this.Close()會終止form之前初始化的所有元件,GC不知不覺開始回收記憶體。。。。

本文的主題在這個return之後發生了。return一完成,它退到哪兒了?對,之前form constructor的BeginAuth之後,也就是說,form還沒有“出生”就已經被“墮”了。但被“墮”不等於什麼也沒有(null),畢竟“屍骨”猶在。MainForm在得知sub-form constructor返回以後就會執行類似顯示form的方法Show()。要秀就要拿到form控制程式碼,但老子(mainform)拿到的卻是一個夭折的孩子。。。當然怎麼show也於事無補了。悲慘的Cannot access a disposed object異常就這樣發生了。由於是從Mainform觸發,它會直接影響主程式,導致程式崩潰。

知道了來龍去脈,那麼怎樣避免呢?很簡單,

1.    不要在constroctor沒有做完之前就任意終止資源(原則性)
        拿示例來說的話,就是不要將BeginAuth方法置於構造方法內,置於Form_load()方法中不失為一良策。

2.       在拿來show之前要判斷是否為空或已被終止(輔助性)
 

 if (subForm!= null && !subForm.IsDisposed)

    subForm.Show();

 

轉者注:我的問題在於開了一個執行緒在關閉視窗前沒有把它關掉,所以我在視窗關閉事件加入執行緒的Abort(),這個問題就解決了...

相關文章