组件的初始化和终止,为什么实现 Dispose
组件由其构造函数(在 Visual Basic 中为 SubNew)初始化,由其析构函数(在 Visual Basic 中为 SubFinalize)销毁。当创建组件的实例时调用组件的构造函数;之后不能再调用此构造函数。在垃圾回收销毁组件并回收其内存之前调用析构函数。
Visual Basic 注意 |
---|
在以前版本的 Visual Basic 中,Initialize 和 Terminate 事件起到与构造函数和析构函数相同的作用。 |
等待垃圾回收
当垃圾回收确定组件不能再由任何执行代码访问后,公共语言运行库将调用该组件的析构函数。如果对组件的所有引用都已释放,或者对组件的唯一引用由特定的对象保持,而该对象以同样的方式与所有执行代码隔离(例如循环引用的情况),则将发生上述情况。
鉴于用户使用完组件与调用组件的析构函数之间可能有一个延迟,在 .NET Framework 组件的生存期中另外引入了一步:如果组件获取系统资源(如数据库连接或 Windows 系统对象的句柄),则应实现 IDisposable 接口,并提供 Dispose 方法以便组件的用户可以选择何时释放那些资源。
组件的生存期
类型初始化:当创建组件的第一个实例时,执行的第一个代码是任何共享的初始化代码。对任何共享成员的引用都将导致执行共享构造函数。这包括任何初始化的共享字段(成员变量)和可能存在的共享构造函数 (SharedSubNew)。在下列代码中,为整个类创建了引用字体。
注意 |
---|
与 Shared 相对应的 C# 关键字是 static,这是为了不与 Visual Basic 中的 Static 关键字混淆。 |
何时应实现 Dispose 方法?
如果组件从 Component 继承,系统会提供 Dispose 的默认实现。可重写此实现以提供自定义清理代码。如果通过创建 IComponent 的自定义实现生成组件,则应实现 IDisposable 以便为组件提供 Dispose 方法。
如果组件分配了系统对象、数据库连接或其他应在用户使用完组件后立即释放的短缺资源,则组件需要 Dispose 方法。
如果组件有对其他对象的引用,而那些对象具有 Dispose 方法,则也应实现 Dispose 方法。
为什么实现 Dispose?
根据系统活动的不同,在用户使用完组件和垃圾回收检测到组件的代码不可访问之间的时间间隔可能不可预知。如果未提供 Dispose 方法,则在这段间隔期内,组件将一直控制其资源。
最坏情况的方案
设想一下使用数据库连接却没有 Dispose 方法的服务器组件。在有大量内存的服务器上,您可能创建并释放组件的许多实例,而不会对可用内存有太大影响。在此情况下,当释放了对组件的引用后,垃圾回收可能在一段时间内不销毁组件。
最后,所有可用的数据库连接可能都被已释放但尚未销毁的组件占用了。即使服务器的内存够用,它也可能无法响应用户请求。