IDisposable接口

我知道IDisposable接口,它在.net中使用,但我心中有一个问题,如果我正在编写所有托管代码,那么实现IDisposable接口是否有意义?

我知道何时以及如何使用Idisposible,但我的问题是,如果我正在编写所有托管代码说一个简单的类没什么昂贵的,所以如果我在这个类中实现IDisposable并做一些清理,如释放一些全局值,它是否有意义?

不,您可能不需要使用IDisposble接口。 但是,它建议在某些情况下(我可能会在以后添加更多,因为我记得:)):

  1. 你的类有很多对象,并且有很多交叉引用。 即使它全部被管理,GC也可能因为活动引用而无法回收内存。 您有机会(除了编写终结器之外)解开引用并按照您附加它们的方式分解链接。 因此,您正在帮助GC回收内存。

  2. 你有一些流是开放的,直到类的对象死亡。 即使管理这些文件/网络等实现,它们也会深入到Win32模式下的句柄。 因此,您有机会编写Dispose方法,您可以在其中关闭流。 GDI对象也是如此,还有更多。

  3. 您正在编写一个使用非托管资源的类,并且您希望将程序集发送给第三方。 您最好使用一次性图案,以确保您可以释放手柄,以避免泄漏。

  4. 感谢supercat:您的类实现了许多事件处理程序并将它们连接到事件。 暴露事件的类的对象,如Form等,将不会被GC释放,因为类(可能)的本地实现仍然挂钩到这些事件中。 你可以在Dispose解开那些事件处理程序; 再次帮助GC。

嗯……我现在记不起来了,但是如果这个类的行为很复杂,你可能想重新考虑为什么你不想要实现IDisposable接口。

经验法则:如果您的类型具有一个本身就是IDisposable的成员变量或者它是非托管的,那么您需要实现IDisposable。 GC在.NET中是不确定的,IDisposable为您提供了一种确定性的方法,即不回收内存而是回收资源 。 因此,当调用Dispose()时,您的内存不会被GC立即释放,但您可以确定性地清理非托管资源 (例如,确保您的数据库连接已关闭,并且您没有在服务器上进行最大连接)。

如果您有一个需要回收的资源(如文件),您希望具有IDisposible以便显式关闭它而不是等待GC转发它。

很少提到的正确使用iDisposable 至关重要的场景是一个使用寿命短的对象,它接收来自长期存在的对象的事件。 此类对象的Dispose方法必须取消订阅其事件。 如果对象没有取消订阅,则在订阅了其事件的对象符合垃圾收集条件之前,它将不具备垃圾收集的条件; 这很可能永远不会。

例如,某些类型的枚举器需要订阅“对象已更改”消息。 在执行长期运行的程序期间,将成千上万的这样的枚举器被创建是完全合理的。 如果这些调查员没有取消订阅,他们可以有效地阻塞系统,即使他们从不使用除了托管内存之外的任何资源。

请注意,顺便说一句,尽管处理这样一个物体很重要,但添加一个终结器来确保这样的处理是没用的。 如果事件发布者已超出范围,则尝试取消订阅其中一个事件将至多无用且可能存在危险。 由于事件订阅者不能超出范围,除非它收到的所有事件的发布者也超出了范围,终结者只有在没有任何事情要做之后才会被调用。

是的,即使您没有任何托管资源, IDisposable仍然可以提供帮助。 为什么? 因为您可以使用Dispose方法将对象引用重置为null

请注意,这本身并没有释放任何资源,因为垃圾收集是非确定性的(即,它通常不会在您选择的任何时刻运行),但它会破坏对象之间的引用(链接),使其成为可能更有可能的是,某些对象将有资格在GC的下一次运行中进行垃圾收集。

它有道理吗?

不,只有在创建成本昂贵的情况下才能使对象成为一次性物品。