Dispose如果没有被调用过,在GC处理它的对象是就会在对象的 Finally 过程中自动调用它。实际上,Dispose并不不需要你去调用。除非你知道手工提前调用Dispose有什么不得已,否则这个方法迟早会被系统自动调用的。

解决方案 »

  1.   

    在对象的 Finally 过程中自动调用它  -->    在组件对象的 Finalize 过程中自动调用它所有组件(控件)的的父类 Component,如果你打开它的源代码,可以看到        protected override void Finalize()
            {
                try
                {
                    this.Dispose(false);
                }
                finally
                {
                    base.Finalize();
                }
            }这样的代码。例如 DbConnection、Process、Thread 之类的,不是控件,但是是组件。而另外一堆类型,例如 FileStream 等等,也定义了跟 Component.Finalize 一样的(调用 Dispose 的)操作。因此通常你根本用不着调用Dispose,提前调用它反而是浪费时间。只有在你说的明白“为什么要提前调用 Dispose ”的时候才应该纠结 Using、Dispose 的问题。
      

  2.   

    那好,我们做一个实验,新建一个窗体应用程序,添加如下代码:        protected override void WndProc(ref System.Windows.Forms.Message m)
            {
                if (m.Msg != 0x10)
                {
                    base.WndProc(ref m);
                }
                else
                {
                    //Dispose();
                }
            }
    运行,你会发现,窗体关不掉了。去掉注释,则可以关掉。这说明Dispose非但不是“无用”,而且相当有用。那么究竟是谁调用了它呢?
    在Dispose方法内下一个断点,然后F5调试程序,关闭窗体,我们发现它被调用了,我们可以在调用堆栈中清楚地看到,是wmclose这个方法调用了它。幸好,微软公布了.net的源代码,我们可以看到:http://referencesource.microsoft.com/#System.Windows.Forms/ndp/fx/src/winforms/Managed/System/WinForms/Form.cs#835f7070c7e52263private void WmClose(ref Message m) {
                FormClosingEventArgs e = new FormClosingEventArgs(CloseReason, false);
     
                // Pass 1 (WM_CLOSE & WM_QUERYENDSESSION)... Closing
                //
                if (m.Msg != NativeMethods.WM_ENDSESSION) {
                    if (Modal) {
                        if (dialogResult == DialogResult.None) {
                            dialogResult = DialogResult.Cancel;
                        }
                        CalledClosing = false;
     
                        // if this comes back false, someone canceled the close.  we want
                        // to call this here so that we can get the cancel event properly,
                        // and if this is a WM_QUERYENDSESSION, appriopriately set the result
                        // based on this call.
                        //
                        // NOTE: We should also check !Validate(true) below too in the modal case,
                        // but we cannot, because we didn't to this in Everett (bug), and doing so
                        // now would introduce a breaking change. User can always validate in the
                        // FormClosing event if they really need to. :-(
                        //
                        e.Cancel = !CheckCloseDialog(true);
                    }
                    else {
                        e.Cancel = !Validate(true);
     
                        // Call OnClosing/OnFormClosing on all MDI children
                        if (IsMdiContainer) {
                            FormClosingEventArgs fe = new FormClosingEventArgs(CloseReason.MdiFormClosing, e.Cancel);
                            foreach(Form mdiChild in MdiChildren) {
                                if (mdiChild.IsHandleCreated) {
                                    mdiChild.OnClosing(fe);
                                    mdiChild.OnFormClosing(fe);
                                    if (fe.Cancel) {
                                        // VSWhidbey 173789: Set the Cancel property for the MDI Container's
                                        // FormClosingEventArgs, as well, so that closing the MDI container
                                        // will be cancelled.
                                        e.Cancel = true;
                                        break;
                                    }
                                }
                            }
                        }
     
                        //Always fire OnClosing irrespectively of the validation result
                        //Pass the validation result into the EventArgs...
     
                        // VSWhidbey#278060.  Call OnClosing/OnFormClosing on all the forms that current form owns.
                        Form[] ownedForms = this.OwnedForms;
                        int ownedFormsCount = Properties.GetInteger(PropOwnedFormsCount);
                        for (int i = ownedFormsCount-1 ; i >= 0; i--) {
                            FormClosingEventArgs cfe = new FormClosingEventArgs(CloseReason.FormOwnerClosing, e.Cancel);
                            if (ownedForms[i] != null) {
                                //Call OnFormClosing on the child forms.
                                ownedForms[i].OnFormClosing(cfe);
                                if (cfe.Cancel) {
                                    // Set the cancel flag for the Owner form
                                    e.Cancel = true;
                                    break;
                                }
                            }
                        }
     
                        OnClosing(e);
                        OnFormClosing(e);
                    }
     
                    if (m.Msg == NativeMethods.WM_QUERYENDSESSION) {
                        m.Result = (IntPtr)(e.Cancel ? 0 : 1);
                    }
     
                    if (Modal) {
                        return;
                    }
                }
                else {
                    e.Cancel = m.WParam == IntPtr.Zero;
                }
     
                // Pass 2 (WM_CLOSE & WM_ENDSESSION)... Fire closed
                // event on all mdi children and ourselves
                //
                if (m.Msg != NativeMethods.WM_QUERYENDSESSION) {
                    FormClosedEventArgs fc;
                    if (!e.Cancel) {
                        IsClosing = true;
     
                        if (IsMdiContainer) {
                            fc = new FormClosedEventArgs(CloseReason.MdiFormClosing);
                            foreach(Form mdiChild in MdiChildren) {
                                if (mdiChild.IsHandleCreated) {
                                    mdiChild.OnClosed(fc);
                                    mdiChild.OnFormClosed(fc);
                                }
                            }
                        }
     
                        // VSWhidbey#278060.  Call OnClosed/OnFormClosed on all the forms that current form owns.
                        Form[] ownedForms = this.OwnedForms;
                        int ownedFormsCount = Properties.GetInteger(PropOwnedFormsCount);
                        for (int i = ownedFormsCount-1 ; i >= 0; i--) {
                            fc = new FormClosedEventArgs(CloseReason.FormOwnerClosing);
                            if (ownedForms[i] != null) {
                                //Call OnClosed and OnFormClosed on the child forms.
                                ownedForms[i].OnClosed(fc);
                                ownedForms[i].OnFormClosed(fc);
                            }
                        }
                        
                        fc = new FormClosedEventArgs(CloseReason);
                        OnClosed(fc);
                        OnFormClosed(fc);
     
                        Dispose();
                    }
                }
            }
     
    看到函数最后一行了么?就是在这里调用的。那么GC会不会自动调用Dispose方法呢?显然不会。我们可以继续一个实验,新建一个控制台程序,然后编写如下代码:using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;namespace ConsoleApplication1
    {
        class Program : IDisposable
        {
            static void Main(string[] args)
            {
                Program p = new Program();
            }        public void Dispose()
            {
                throw new NotImplementedException();
            }
        }
    }显然,如果Dispose方法被调用,会丢出异常,我们运行这个程序——什么也没有发生。这就说明GC绝对没有这个功能。怎么样让GC的时候触发Dispose呢?我们需要手工写:
    ~Program()
    {
        Dispose();
    }
    C#的析构函数就是Finalize函数。此时再运行,就会调用了。顺便说下,Application.OpenForms集合始终保持着Form窗体的引用,所以除非关闭窗体,否则,GC永远没有可能清理Form对象。
      

  3.   


    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        if (m.Msg != 0x10)
        {
            base.WndProc(ref m);
        }
        else
        {
            //Dispose();
        }
    }补充一点给楼主:
    在用户点击 Close 按钮的时候,会触发 WM_CLOSE (0x0010) 消息,并由 WndProc 进行相应的处理,版主在此地的 demo 就是在 close form 行为触发的时候,略过基类的 WndProc 方法,而在 WndProc 内部会触发对 WmClose 方法的调用,参见版主放出来的源代码链接。所以,当你什么也不做的时候,系统是以 WndProc 为入口对 Dispose 方法调用的。protected override void WndProc(ref Message m) {
        switch (m.Msg) {
            case NativeMethods.WM_NCACTIVATE:
            // ...... 
            case NativeMethods.WM_CLOSE:
                if (CloseReason == CloseReason.None) {
                    CloseReason = CloseReason.TaskManagerClosing;
                }
                WmClose(ref m);
                break;
            case NativeMethods.WM_QUERYENDSESSION:
            // ...... 
        }
    }