我正在对一个大型代码库进行故障排除,我发现的一个反复出现的问题如下:
对象的一个实例Bitmap
被分配给PictureBox
。当需要替换图像时,代码会处置该对象并将其替换为新创建的对象(按此顺序)。当然,解决方案是在处置位图之前将其与控件解除关联。
请注意,这是一个特定的例子,但它可以适用于任何情况。捕获 ObjectDisposed 异常是不够的(没有异常)。在上面的例子中,包含控件抛出了它自己的基于 GDI 的异常:Parameter is not valid
。
我并不是建议采用这种方法。我只是想知道是否有可能检测任意托管对象是否被释放(当然,只要我们有对它的引用)。
简短的回答是“否”。IDispoable
接口不提供任何方法来告知用户代码实现该接口的实例实际上已被释放,而是由编写用户代码的开发人员以这样一种方式编写,即在不再需要实例时将其释放。
当然,您可以创建自己的接口,该接口继承自 IDisposable,添加一个 IsDisposed 属性,并使用实现此接口的类包装您的 IDisposable 类,但这仍然需要用户代码使用该属性才能从中受益。处理此问题的更好方法是修复使用 IDisposable 实例的代码。
.NET 对象处置功能与任何内存管理活动无关,因此它不是任何类型自动固有的。
自从实现了自动内存管理之后,对象析构函数就不再被确定地调用了。程序员应该自己注意释放非托管资源。.NET 中提出的标准方法是 IDisposable(由 c# 编译器使用 using 语句支持),但它可以是任何方式,这取决于程序员,并且应该明确实现。
仅当对象提供此类功能(例如,实现 IDisposable 并提供 IsDisposed 等附加属性)时,您才可以确定是否处置托管对象。
您需要将此功能嵌入到您需要监控的每种类型中。
PictureBox 实现了您需要处理的 Disposed 事件。不幸的是,它不是 IDisposable 的一部分,我们不应该在任何地方期待这个事件,而且其他 .NET 类型(例如 Stream)没有实现它。
调用 Dispose 方法不会终止对象。您可以根据需要以下列方式“处置”对象:
如果应用程序没有达到内存限制,则在应用程序退出时调用析构函数。