什么是确保Dispose在类成员/字段上被调用的正确方法?
什么是确保Dispose在类成员/字段上被调用的正确方法?
我有一个类(myClass),它有一个继承自IDisposable的类成员(myDisposableMem),因此具有Dispose()方法。如果它是一个局部变量,我可以使用using(...) {...}来确保在此对象上调用Dispose()。但它是一个类成员。如何确保在成员上调用已处理?我可以想到两种方法:
1)在类中添加一个finallize(),然后在其中调用myDisposableMem.Dispose()
或者
2)让我的类继承自IDisposible:
public class myClass : IDisposable { ... public void Dispose() { myDisposableMem.Dispose(); } } void main () { using (myClass myObj = new MyClass()) { .... } }
或许还有更好的方法?
Finalization和实现IDisposable不是两个不同的选项;它们应该总是同时完成。你应该总是实现IDisposable并在Dispose()中清理你的资源,这样用户就可以确保非托管资源得到及时清理。你的Dispose()方法应该总是最后调用GC.SuppressFinalize(this)来确保它的终结器不会被调用,原因将在一会儿解释。\n\n当你实现IDisposable时,你应该总是实现~MyObject()。它的目的是给垃圾收集器一个方法,在使用它的人没有自己进行处理时,可以确保您的对象被始终处理。如果你的终结器做的比调用this.Dispose()更多,那么你可能使用它不正确。不是这样的。请参见Ilian Pinzon的下面评论,我显然有一些文档要重新阅读。\n\n它只是一种安全措施。理想情况下,终结器实际上应该从未被调用,因为对象总是明确地处理。当垃圾收集器调用它时,它被强制跳过收集该对象。这反过来意味着它被传递到第二个垃圾收集器代。这反过来意味着该对象将在内存中停留更长的时间,并且最终清理起来更加昂贵。\n\n请参见此处和此处,以获取更多有关应该如何进行操作的信息。\n\n话虽如此,最好的选择是尽可能将这些可处理的对象从类上下文中移出,并将它们作为方法变量。例如,如果你有一个连接到数据库的类,请不要将SqlConnection的主实例存储为字段。相反,让你的公共方法创建自己的连接,并根据需要将它们传递给私有方法。这有两个优点:首先,它意味着你可以在using块中声明你的SqlConnections并且完成它。其次,消除那个“全局”状态将有助于线程安全,如果你需要它。(对于SqlConnection,还有其他特定的优点,但这些是一般的。)
如果一个对象或者一段代码持有一个IDisposable对象,并且没有理由相信其他对象或代码会调用Dispose方法,则称其“拥有”该对象或代码。拥有存储在局部变量中的IDisposable的代码,通常在放弃该变量之前必须调用Dispose方法,或将其交给预期要接收所有权的其他代码或对象。拥有存储在字段中的IDisposable的对象通常必须实现IDisposable本身;其Dispose方法应检查该字段是否为null,如果不是,则调用其Dispose方法。\n\n需要注意的是,仅仅持有对IDisposable的引用并不意味着应该调用其Dispose方法。只有在有合理的期望没有其他代码会调用其Dispose方法的情况下,才应该只对持有的IDisposable进行Dispose调用。\n\n对象应该仅在可以在未知线程上下文中以有用和安全的方式执行某些清理时才重写Finalize方法。一般而言,对象不应在Finalize方法中调用其他IDisposable对象的Dispose方法,因为(与某些源代码相反)尽管这些对象保证存在,但以下情况中最有可能出现以下情况之一:\n\n1.其他对象可能仍在某处使用,这种情况下对其调用Dispose方法可能是不安全的。\n\n2.其他对象可能已经调用了其Finalize方法,在这种情况下,Dispose调用最多也是多余的,而且可能是不安全的。\n\n3.其他对象可能已经安排调用其Finalize方法,在这种情况下,Dispose可能是安全的,但很可能是多余的。\n\n4.其他对象可能不支持线程安全的清理,在这种情况下,调用Dispose可能不是多余的,但是不安全的。\n\n5.正当Finalizer可以实际变得可用时,它想要做的任何事情都可能是无意义的(这种情况可能出现在事件订阅中)。\n\n简而言之,如果一个对象拥有一个IDisposable,通常应该假定如果它可以在最终器线程上下文中安全地清理自己,它就会自行处理,如果不能,则不应该试图强制执行。