现在我明白当我完成一个实现IDisposable
的资源时,我应该调用Dispose()
方法来清理资源。
我应该在多大程度上做到这一点。
我的例子是:
我在代码中创建NotifyIcon
,所以我做了类似的事情:
var icon = new Icon(...);
var contextMenu = new ContextMenu(...);
var contextMenuButton1 = new MenuItem(...);
var contextMenuButton2 = new MenuItem(...);
var contextMenuButton3 = new MenuItem(...);
// ...
var notifyIcon = new NotifyIcon(...);
所有这些都有Dispose()
方法。通常我只会继续引用notifyIcon
而只是处理它。
但是,它不会丢弃图标或上下文菜单或其项目,所以我实际上应该保留对所有内容的引用,或者至少有一个List<IDisposable>
?
或者我可以假设,因为垃圾收集器会为我调用这些处理器的范围(当我处理NotifyIcon时)?
答案 0 :(得分:2)
这很大程度上取决于场景。例如,在许多UI框架中,向父控件/容器添加类似菜单项或图标的内容会使父承担该项的责任。因此,处理父母将同时处置所有祖先。所以:如果我们假设您正在创建的这些新控件将添加到UI中,则不会:您通常不需要手动执行任何操作。但是,如果您经常添加/删除控件,那么您将需要弄清楚何时取得元素的所有权(即如果您从UI中删除它,它现在是“你的”,而不是用户界面 - 处理它是你的责任。)
答案 1 :(得分:0)
通常,这就是using语句的用途,例如:
using (var icon = new Icon(...))
{
}
using语句一旦结束就调用Dispose方法(即使里面有异常,它仍然可以正确处理变量)。您甚至可以“链接”它们以减少嵌套:
using (var icon = new Icon(""))
using (var icon2 = new Icon(""))
using (var icon3 = new Icon(""))
{
}
您想尽快调用Dispose。如果不这样做,它仍然会在某个时刻被调用,通常是在对象的最终确定期间,但这可能已经太晚了(例如,处理文件句柄将允许打开另一个文件句柄,而如果你不要很快处理它,第二次调用将抛出异常)。
首先是Dispose方法的原因是因为Icon在后台有一些本机资源(它使用本机Icon对象,这都与Windows和GDI +有关)。这些资源“稀缺”(更好的例子是文件句柄),因此您不希望等待GC最终收集它们 - 这样做成本更高(如果广泛完成,最终确定会产生非常重要的成本)和可以阻止对资源的访问(即使使用Icon,我还记得每个进程只能分配这么多原生位图的问题,然后你就饿了。)
如果你不关心费用,如果资源不够重要,如果using
或Dispose
比你的价值更麻烦 - 你不会必须调用Dispose。它最终将被调用。
作为你应该手动调用dispose的例子:文件,流,套接字,大块本机内存。
答案 2 :(得分:0)
来自MSDN:`
当创建新的NotifyIcon时,... [it]将存在,直到其容器将其释放到垃圾回收。
如果使用带有System.ComponentModel.Container
所拥有的容器(通常为Form
)的构造函数,则在处置容器时(即表单关闭时)将调用Dispose。 / p>
上面链接的MSDN文档中的示例以这种方式使用Form的容器。
如果您使用默认构造函数,则没有容器,您必须自己管理NotifyIcon的生命周期,并在完成后将其处置。
答案 3 :(得分:-2)
垃圾收集器最终将为所有对象调用Dispose(假设它们是根据IDisposable指南实现的),但作为最佳实践,您应该始终自己这样做。这只是一种最佳实践,它还可以让您检测可能存在问题的区域(例如,大型Image
在内存中保留的时间太长 - 因为您将手动处理它,您的应用程序将抛出异常,如果它试图在你不打算的地方使用它。)
using (var icon = new Icon(...))
using (var contextMenu = new ContextMenu(...))
using (var contextMenuButton1 = new MenuItem(...))
using (var contextMenuButton2 = new MenuItem(...))
using (var contextMenuButton3 = new MenuItem(...))
{
// ...
}
this.notifyIcon = new NotifyIcon(...);
由于您要存储(我在此代码示例中假设)this.notifyIcon
值,您的类还必须实现IDisposable
并在那里调用this.notifyIcon.Dispose()
。
编辑:对于那些说GC不会调用Dispose()
的注释 - 实现IDisposable
的标准模式是实现调用this.Dispose()
的析构函数 - 因为GC确实调用了析构函数/ finalizer它也会间接调用Dispose()
。 http://msdn.microsoft.com/en-us/library/ms244737.aspx