none
我想问个windows编程的初级问题 RRS feed

  • 问题

  •  private System.ComponentModel.IContainer components = null;
    
    
    
    //这是我做的一个form1的一断代码 components是vs自动生成的
    
    //为什么要讲components设为空
    
     protected override void Dispose(bool disposing)
    
            {
    
                if (disposing && (components != null))
    
                {
    
                    components.Dispose();
    
                }
    
                base.Dispose(disposing);
    
            }
    
    //这里从写的dispose方法是被谁调用 我不明白 是由谁来调用了这个方法
    还有就是dispose是释放的是components的资源 这里不明白是怎么一回事
    请大虾给讲讲我是windows入门新手
    看的是北京大学出版社的 那本C# windows编程
    这个编译器自动生成的部分没看懂 看msdn的例子也没看懂 请大虾指教
    2009年7月9日 13:09

答案

  • Hi ,
      这个是Winform编程吧~你提的问题其实涉及到.Net 垃圾回收的C#编程相关方面的问题。它提供了集中方式来让我们开发者来处理垃圾回收。一下两个方法概念是垃圾回收的时候要遇到的:
    1.Finalize终结器是CRL提供的一个机制, 如果一个类实现了Finalize方法,那么当该类对象被垃圾回收时,垃圾回收器会调用Finalize方法.我们需要在重写Finalize方法中,处理 非托管资源的释放.
    2.Dispose是重写接口IDispose的方法。这个是一种垃圾回收的设计模式。因为.net编程中使用的资源包括托管和非托管两种。
    托管资源可以GC自动回收,但非托管资源比如网络连接、图片、文件流等对象GC不能够直接回收。这些资源非常的珍贵,需要我们在使用完毕以后立即释放掉。就需要我们来提供个一个释放机制。 这里重写的Dispose(bool disposing),在使用完类对象后,可以调用此方法释放非托管资源,无需等到该类对象被GC垃圾回收.
       你这里代码里也提供了一个重写Dispose方法,你可以重新修改代码,如果你使用了非托管资源,可以再整理实现非托管资源的释放。其它使用此对象的时候,可以根据需要要不要调用Dispose方法。Dispose(bool disposing),这个参数只是为了区分这个方法是谁调用的,如果不是客户端调用的,可以组织GC多次调用此对象的Finalized方法。提高性能。
       
      呵呵你的问题一点都不基础啊,其实这个垃圾回收问题在.net开发中,可以说非常重要~
    你有兴趣可以自己搜索一些net垃圾回收和内存管理的文章。网上很多~

    Frank.Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    老徐的博客:http://frank_xl.cnblogs.com
    2009年7月9日 14:10
    版主
  • 如果你创建的对象的类型实现了IDisposable,那么你必须调用其Dispose方法释放资源。
    一些类自动调用Dispose方法,例如Windows表单类库中的Form类在调用Show方法之后会在窗口关闭时调用自己的Dispose方法。
    局部变量应该在退出作用域的之前调用Dispose方法。如果一个类的一个成员变量的类型实现了IDisposable,那么这个类也必须实现IDisposable,并且在对Dispose方法的实现中确保所有可以Dispose的成员变量都已经被Dispose了。

    Please mark the post answered your question as the answer, and click the chartreuse pyramid floating over nothingness/null to mark other helpful posts as helpful. This posting is provided "AS IS" with no warranties, and confers no rights.
    Visual C++ MVP
    2009年7月9日 16:56
    版主
  • 就用途而言Dispose()和Finalize()(或称C#析构函数)是相同的,都是用来释放昂贵资源的。但前者是“确定性终结”,后者是“不确定终结”
    原因是:Dispose()由客户程序调用;Finalize()由垃圾回收机制调用,该调用发生在一个谁也不知道的时间。
    举个简单的例子,来说明Dispose()的调用。
    有一个实现了IDisposable接口的类如:
    public class MyComponent : IDisposable
    {
         //有很多方法
         ......
         public void SomeMethod(){}
        
         public void Dispose()
         {
                //释放资源的代码
                ......
         }
    }
    在程序代码中调用的方法有两种:
    1、static void Main()
    {
        MyComponent  m_MyComponent  = new MyComponent ();
         try
        {         
              m_MyComponent.SomeMethod();
         }
         finally
        {
                IDisposable m_Disposable = m_MyComponent as IDisposable;
                if(m_Disposable!= null)
                {
                       m_Disposable.Dispose(); //因为是客户程序调用,因此可以说是“确定性终结”
                }
         }
    }
    第二种用法:
    2。static void Main()
    {
         MyComponent  m_MyComponent  = new MyComponent ();
         using(m_MyComponent)
        {
           m_MyComponent.SomeMethod();
        }
    }
    使用using语句,编译器会将第二种代码转换成第一种,这样调用起来就很方便,不需要用第一种方法那么繁琐。您也会看到SqlConnetion中有类试的用法。
    在了解了Dispose()和Finalize()后,再来看看您提到的Dispose(bool disposing)
    Dispose()和Dispose(bool disposing)很容易混淆。
    我们来看看微软自己实现的所有组件父类Component,定义如下:
    //继承MarshalByRefObject则表明组件是可以跨应用程序域的
    public class Component : MarshalByRefObject, IComponent
    {
     //有关资源释放的方法代码,其它代码略
            //Dispose()就是一个模板方法
            public void Dispose() {
                Dispose(true);//注意Dispose(bool disposing)方法在此调用
                GC.SuppressFinalize(this);//该方法将自己从垃圾回收的终结队列中取消,这样Finalize()将不会被调用
            }
            //注意Dispose(bool disposing)是保护型的虚方法,是一个钩子方法
            protected virtual void Dispose(bool disposing) {
                if (disposing) {
                    lock(this) {
                        if (site != null && site.Container != null) {
                            site.Container.Remove(this);
                        }
                        if (events != null) {
                            EventHandler handler = (EventHandler)events[EventDisposed];
                            if (handler != null) handler(this, EventArgs.Empty);
                        }
                    }
                }
            }
            //等同Finalize() 对于一些客户程序未调用Dispose()的情况,可以在这里补救。
            ~Component() {
                Dispose(false);
            } 
    }
    采用虚的保护的方法Dispose(bool disposing) 设计原因是继承Component的组件类不用实现IDisposable接口的Dispose(),但是由于组件子类的资源只有子类才知道如何释放故采用了钩子方法,在子类

    中实现Dispose(bool disposing)。因此您需要写您提供的代码:
    if (disposing && (components != null))
    {
       components.Dispose();//释放子类知道的资源
    }
    也需要释放父类的资源故要调用base.Dispose(disposing);
    如果对模板方法不熟悉可以查看head first系列的设计模式一书。

    2009年7月9日 18:32
  • 你好!
        大家关于Dispose大家已经做了详细的解释,我想你可能对components这个字段还有一些疑问,我详细解释一下:
        这个字段用做组件的容器,比如你向窗体添加了一个Timer组件,则VS生成如下代码:
    private System.ComponentModel.IContainer components = null;//这句在没有添加Timer前就生成了,用于声明一个容器

    。。。
                this.components = new System.ComponentModel.Container();//初始化容器

                this.timer1 = new System.Windows.Forms.Timer(this.components);//将Timer与容器相关联

        实际上那个重写的Dispose方法的作用是释放这些添加的组件所占用的资源(例如Timer等)

        希望这个解释对你有帮助!
    周雪峰
    2009年7月10日 7:05
    版主

全部回复

  • Hi ,
      这个是Winform编程吧~你提的问题其实涉及到.Net 垃圾回收的C#编程相关方面的问题。它提供了集中方式来让我们开发者来处理垃圾回收。一下两个方法概念是垃圾回收的时候要遇到的:
    1.Finalize终结器是CRL提供的一个机制, 如果一个类实现了Finalize方法,那么当该类对象被垃圾回收时,垃圾回收器会调用Finalize方法.我们需要在重写Finalize方法中,处理 非托管资源的释放.
    2.Dispose是重写接口IDispose的方法。这个是一种垃圾回收的设计模式。因为.net编程中使用的资源包括托管和非托管两种。
    托管资源可以GC自动回收,但非托管资源比如网络连接、图片、文件流等对象GC不能够直接回收。这些资源非常的珍贵,需要我们在使用完毕以后立即释放掉。就需要我们来提供个一个释放机制。 这里重写的Dispose(bool disposing),在使用完类对象后,可以调用此方法释放非托管资源,无需等到该类对象被GC垃圾回收.
       你这里代码里也提供了一个重写Dispose方法,你可以重新修改代码,如果你使用了非托管资源,可以再整理实现非托管资源的释放。其它使用此对象的时候,可以根据需要要不要调用Dispose方法。Dispose(bool disposing),这个参数只是为了区分这个方法是谁调用的,如果不是客户端调用的,可以组织GC多次调用此对象的Finalized方法。提高性能。
       
      呵呵你的问题一点都不基础啊,其实这个垃圾回收问题在.net开发中,可以说非常重要~
    你有兴趣可以自己搜索一些net垃圾回收和内存管理的文章。网上很多~

    Frank.Xu Lei--谦卑若愚,好学若饥
    专注于.NET平台下分布式应用系统开发和企业应用系统集成
    Focus on Distributed Applications Development and EAI based on .NET
    老徐的博客:http://frank_xl.cnblogs.com
    2009年7月9日 14:10
    版主
  • 如果你创建的对象的类型实现了IDisposable,那么你必须调用其Dispose方法释放资源。
    一些类自动调用Dispose方法,例如Windows表单类库中的Form类在调用Show方法之后会在窗口关闭时调用自己的Dispose方法。
    局部变量应该在退出作用域的之前调用Dispose方法。如果一个类的一个成员变量的类型实现了IDisposable,那么这个类也必须实现IDisposable,并且在对Dispose方法的实现中确保所有可以Dispose的成员变量都已经被Dispose了。

    Please mark the post answered your question as the answer, and click the chartreuse pyramid floating over nothingness/null to mark other helpful posts as helpful. This posting is provided "AS IS" with no warranties, and confers no rights.
    Visual C++ MVP
    2009年7月9日 16:56
    版主
  • 就用途而言Dispose()和Finalize()(或称C#析构函数)是相同的,都是用来释放昂贵资源的。但前者是“确定性终结”,后者是“不确定终结”
    原因是:Dispose()由客户程序调用;Finalize()由垃圾回收机制调用,该调用发生在一个谁也不知道的时间。
    举个简单的例子,来说明Dispose()的调用。
    有一个实现了IDisposable接口的类如:
    public class MyComponent : IDisposable
    {
         //有很多方法
         ......
         public void SomeMethod(){}
        
         public void Dispose()
         {
                //释放资源的代码
                ......
         }
    }
    在程序代码中调用的方法有两种:
    1、static void Main()
    {
        MyComponent  m_MyComponent  = new MyComponent ();
         try
        {         
              m_MyComponent.SomeMethod();
         }
         finally
        {
                IDisposable m_Disposable = m_MyComponent as IDisposable;
                if(m_Disposable!= null)
                {
                       m_Disposable.Dispose(); //因为是客户程序调用,因此可以说是“确定性终结”
                }
         }
    }
    第二种用法:
    2。static void Main()
    {
         MyComponent  m_MyComponent  = new MyComponent ();
         using(m_MyComponent)
        {
           m_MyComponent.SomeMethod();
        }
    }
    使用using语句,编译器会将第二种代码转换成第一种,这样调用起来就很方便,不需要用第一种方法那么繁琐。您也会看到SqlConnetion中有类试的用法。
    在了解了Dispose()和Finalize()后,再来看看您提到的Dispose(bool disposing)
    Dispose()和Dispose(bool disposing)很容易混淆。
    我们来看看微软自己实现的所有组件父类Component,定义如下:
    //继承MarshalByRefObject则表明组件是可以跨应用程序域的
    public class Component : MarshalByRefObject, IComponent
    {
     //有关资源释放的方法代码,其它代码略
            //Dispose()就是一个模板方法
            public void Dispose() {
                Dispose(true);//注意Dispose(bool disposing)方法在此调用
                GC.SuppressFinalize(this);//该方法将自己从垃圾回收的终结队列中取消,这样Finalize()将不会被调用
            }
            //注意Dispose(bool disposing)是保护型的虚方法,是一个钩子方法
            protected virtual void Dispose(bool disposing) {
                if (disposing) {
                    lock(this) {
                        if (site != null && site.Container != null) {
                            site.Container.Remove(this);
                        }
                        if (events != null) {
                            EventHandler handler = (EventHandler)events[EventDisposed];
                            if (handler != null) handler(this, EventArgs.Empty);
                        }
                    }
                }
            }
            //等同Finalize() 对于一些客户程序未调用Dispose()的情况,可以在这里补救。
            ~Component() {
                Dispose(false);
            } 
    }
    采用虚的保护的方法Dispose(bool disposing) 设计原因是继承Component的组件类不用实现IDisposable接口的Dispose(),但是由于组件子类的资源只有子类才知道如何释放故采用了钩子方法,在子类

    中实现Dispose(bool disposing)。因此您需要写您提供的代码:
    if (disposing && (components != null))
    {
       components.Dispose();//释放子类知道的资源
    }
    也需要释放父类的资源故要调用base.Dispose(disposing);
    如果对模板方法不熟悉可以查看head first系列的设计模式一书。

    2009年7月9日 18:32
  • 你好!
        大家关于Dispose大家已经做了详细的解释,我想你可能对components这个字段还有一些疑问,我详细解释一下:
        这个字段用做组件的容器,比如你向窗体添加了一个Timer组件,则VS生成如下代码:
    private System.ComponentModel.IContainer components = null;//这句在没有添加Timer前就生成了,用于声明一个容器

    。。。
                this.components = new System.ComponentModel.Container();//初始化容器

                this.timer1 = new System.Windows.Forms.Timer(this.components);//将Timer与容器相关联

        实际上那个重写的Dispose方法的作用是释放这些添加的组件所占用的资源(例如Timer等)

        希望这个解释对你有帮助!
    周雪峰
    2009年7月10日 7:05
    版主