假如我们程序有两个窗口 Form1、Form2; 当我们关闭一个窗口的时候,会发出一个 终止响应,并将该窗口对象送入终止队列,公共语言运行库的垃圾回收器跟踪着这个对象的生存期,此时就会调用此对象的基类,比如 Form2的Dispose方法,用于销毁对象并收回资源。

如果我们在 Form2 窗体中建立一个关闭后显示 Form1 的窗体,代码如下:

Public Class Form2
Private Sub Form2_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
Frm1.Show()
End Sub
End Class

这里我们用了 Form2 窗体的 FormClosed 事件可以解决 关闭 Form2 窗体后,Form1 没显示出来而导致程序进入永久运行状体。

然而,大家可能回发现一个问题,如果我们再次点击 Button1 按钮后,Form2 它能原模原样的显示出来吗?

答案是否定的,它不仅不显示,还会导致程序出错:错误如下图:

构造函数的作用:

其实方法很简单:

我只要判断一下 Form2 是否被销毁就行了,如果销毁了我们就用 New 函数构造 一个 Form2 窗口实例,这样,我们又能重新把 Form2 窗口给显示出来。

所以我们用 form2.IsDisposed就可以来判断

Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If frm2 Is Nothing Or frm2.IsDisposed Then '判断对象是否被销毁
frm2 = New Form2()
End If
Me.Hide()
frm2.Show()
End Sub
End Class
Public Class Form2
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Me.Hide()
frm1.Show()
End Sub
Private Sub Form2_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
Frm1.Show()
End Sub
End Class

这下完善多了,两个窗体之间的切换也不会有这么多 别扭的问题了。

对VB.NET的窗体实例的创建与销毁的过程我们来分析一下

一个窗体类,比如 Form1 类是通过调用其基类,就是 Form 类的 New 方法来创建实例、 Dispose方法来销毁实例。

我们来看看 Windows  窗体设计器生成的代码 :

Public Sub New()
MyBase.New()
'该调用是 Windows 窗体设计器所必需的。
InitializeComponent()
'在 InitializeComponent() 调用之后添加任何初始化
End Sub
'窗体重写处置以清理组件列表。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

MyBase 关键字的行为类似 于引用类的当前实例的基类的对象变量。

MyBase 常用于访问在派生类中被重写或 隐藏的基类成员。在这段代码中,MyBase 指的当然就是 System.Windows.Forms.Form 类了。构造对象时用的New方法是显式调用的,没什么好解说的。

析构函数但善后工作 :

所谓析构:析构函数(destructor) 与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。

备注

  • 不能在结构中定义析构函数,只能对类使用析构函数。

  • 一个类只能有一个析构函数。

  • 无法继承或重载析构函数。

  • 无法调用析构函数,它们是被自动调用的。

  • 析构函数既没有修饰符,也没有参数。

程序员无法控制何时调用析构函数,因为这是由垃圾回收器决定的。  垃圾回收器检查是否存在应用程序不再使用的对象。  如果垃圾回收器认为某个对象符合析构,则调用析构函数(如果有)并回收用来存储此对象的内存。  程序退出时也会调用析构函数。

可以通过调用 Collect 强制进行垃圾回收,但大多数情况下应避免这样做,因为这样会导致性能问题。

在 vb.net 中,使用名称为 Finalize 的“垃圾清理” Sub 过程类创建析构函数。访问修饰符为 Protected(受保护的 )和  Overrides 关键字。通常变量为 Nothing 时,表示该变量被置空,从内存清除对象,回收对象占用的系统资源。

总之:不要在类的 Finalize 方法中对 Connection、DataReader 或任何其他托管对象调用 CloseCollect Dispose。在终结器中,应该仅释放类直接拥有的非托管资源。如果您的类不拥有任何非托管资源,则不要在类定义中包括 Finalize 方法。

一句话:托管的就不要管,但非托管的你就非管不可

如例:

Module Module1
Private Class First
Protected a As Object = New Object '用 Protected 声明,好让派生类也能方法此变量
Public Sub New() '无参数的构造函数
a = "析构函数被调用"
Console.WriteLine("First 类中的{0}", a)
End Sub
Protected Overrides Sub Finalize() '析构函数
If a IsNot Nothing Then
a = Nothing '把引用类型变量清空
GC.Collect() '程序退出后,由 CLR 的垃圾回收机制 GC 自己确认何时清理回收
End If
End Sub
End Class
Private Class Second
Inherits First
Public Sub New()
Console.WriteLine("Second 类中的{0}", a)
End Sub
End Class
Private Class Third
Inherits Second
Public Sub New()
Console.WriteLine("Third 类中的{0}", a)
End Sub
End Class
Sub Main()
Dim t As New Third
Console.Read()
End Sub
End Module

如图:

Form.Dispose 方法是重写自 Control.Dispose 方法的,那么 Control.Dispose 方法的含义又是怎么样的?

它的作用就是:释放由 Control 占用的非托管资源,还可以另外再释放托管资源。

当它参数中的 disposing 为 true 时,则释放 托管资源 和 非托管资源;为 false 则仅释放 非托管资源。

Form 类的 disposing 为 true。在关闭窗体时自动调用dispose的功能是得益于.net的公共语 言运行库,运行库自动处理对象布局和管理对对象的引用,当不再使用对象时释放它们。其生存期以这种方式来管理的对象称为托管数据。

自动内存管理消除内存泄漏以及其他一些常见的编程错误。任何类型的 Dispose 方法都应该释放它拥有的所有资源。它还应该通过调用其父类型的 Dispose 方法释放其基类型拥有的所有资源。该父类型的 Dispose 方法应该释放它拥有的所有资源并同样也调用 其父类型的 Dispose 方法,从而在整个基类型层次结构中传播该模式。要确保始终正确地清理资源,Dispose 方法应该可以被多次安全调用而不引发任何异常。

可是,如果系统问题或应用程序调用上出了问题,不能正常调用Dispose怎么办?

这时,如果通过 Dispose 还释放不干净或没有调用Dispose,系统的垃圾回收器会调用对象的 Finalize 方法进行清除。由于执行 Finalize 方法会大大减损性能,所以我们不 会一开始就用它去进行清除工作。

这是我们能想起了一个重要的问题:“如果总是在模块、类和窗体中定义的全局变量来处理,由于访问范围太大,会不会有安全性的问题?

当然,我们可以试试其他的解决方案。

最新文章

  1. 探索ASP.NET MVC5系列之~~~6.Session篇(进程外Session)
  2. java基础-泛型3
  3. [转]ASP.NET Web API(三):安全验证之使用摘要认证(digest authentication)
  4. 关于app.config不能即时保存读取的解决方案
  5. [bzoj 1064][NOI2008]假面舞会(dfs判断环)
  6. 深度学习 vs 机器学习 vs 模式识别
  7. Java中的main()方法详解
  8. OSSEC 安装执行./install.sh详细信息
  9. 看了些关于rem的知识点,在这做个自我总结归纳
  10. Android ContentProvider完整案例
  11. thymeleaf模板引擎shiro集成框架
  12. python函数式编程之yield表达式形式
  13. 火狐兼容window.event.returnValue=false;
  14. 使用pyton在本地指定目录模拟服务器
  15. Ubuntu 16.04 强制使用ipv4安装apt-get
  16. HTTP协议(TCP/IP)
  17. lesson2-cnn-fastai
  18. Odoo进销存业务思路浅析
  19. virtualbox+vagrant学习-3-Vagrant Share-4-Vagrant Connect
  20. 有道云笔记同步IT笔试面试资源

热门文章

  1. iOS开发 XML解析和下拉刷新,上拉加载更多
  2. UIView的一些常用属性和方法
  3. 生成树题目泛做(AD第二轮)
  4. BestCoder Round #20 部分题解(A,B,C)(hdu5123,5124,5125)
  5. 做了一个js的拉动遮罩层,两个图片分别显示的效果
  6. 配置chrome支持本地(file协议)ajax请求
  7. Java 正则提取数字串
  8. Theme.AppCompat.Light报错
  9. 为什么和其他语言相比C语言是快速的语言
  10. ubuntu centos debina