C#2008
我已经为此工作了一段时间,但我仍然对在代码中使用finalize和dispose方法感到困惑。我的问题如下:
我知道在处理非托管资源时我们只需要一个终结器即可。但是,如果存在调用非托管资源的托管资源,是否仍需要实现终结器?
但是,如果我开发的类不直接或间接使用任何非托管资源,是否应该实现,IDisposable以允许该类的客户端使用“使用语句”?
IDisposable
实现IDisposable只是为了使您的类的客户端能够使用using语句是否可行?
using(myClass objClass = new myClass()) { // Do stuff here }
public class NoGateway : IDisposable
{ private WebClient wc = null;
public NoGateway() { wc = new WebClient(); wc.DownloadStringCompleted += wc_DownloadStringCompleted; } // Start the Async call to find if NoGateway is true or false public void NoGatewayStatus() { // Start the Async's download // Do other work here wc.DownloadStringAsync(new Uri(www.xxxx.xxx)); } private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { // Do work here } // Dispose of the NoGateway object public void Dispose() { wc.DownloadStringCompleted -= wc_DownloadStringCompleted; wc.Dispose(); GC.SuppressFinalize(this); }
}
有关源代码的问题:
因此,在示例中,我的类称为NoGateway,客户端可以使用和处置此类,如下所示:
using(NoGateway objNoGateway = new NoGateway()) { // Do stuff here }
当执行到达using块的末尾时,将自动调用Dispose方法,还是客户端必须手动调用dispose方法?即
NoGateway objNoGateway = new NoGateway(); // Do stuff with object objNoGateway.Dispose(); // finished with it
WebClient
NoGateway
推荐的IDisposable模式在此处。在编写使用IDisposable的类时,通常应使用两种模式:
当实现不使用非托管资源的密封类时,只需像常规接口实现一样实现Dispose方法:
public sealed class A : IDisposable { public void Dispose() { // get rid of managed resources, call Dispose on member variables... } }
实现未密封的类时,请执行以下操作:
public class B : IDisposable { public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { // get rid of managed resources } // get rid of unmanaged resources } // only if you use unmanaged resources directly in B //~B() //{ // Dispose(false); //} }
请注意,我尚未在中声明终结器B;仅当您有要处理的实际非托管资源时,才应实现终结器。CLR处理可终结对象与不可终结对象的方式有所不同,即使SuppressFinalize被调用也是如此。
B
SuppressFinalize
因此,除非必须这样做,否则不应该声明终结器,但是如果类的继承者Dispose直接使用非托管资源,则可以给它们的继承者一个钩子来调用您自己并实现终结器:
Dispose
public class C : B { private IntPtr m_Handle; protected override void Dispose(bool disposing) { if (disposing) { // get rid of managed resources } ReleaseHandle(m_Handle); base.Dispose(disposing); } ~C() { Dispose(false); } }
如果您不直接使用非托管资源(SafeHandle并且朋友不声明,因为他们声明了自己的终结器),则不要实现终结器,因为GC处理终结类的方式有所不同,即使您以后取消终结器也是如此。还要注意,即使B没有终结器,它仍然会调用SuppressFinalize以正确处理实现终结器的所有子类。
SafeHandle
当一个类实现IDisposable接口时,这意味着当您结束使用该类时,应该删除一些非托管资源。实际资源封装在类中;您无需明确删除它们。只需Dispose()将类调用或包装在中即可using(...) {}确保在必要时清除所有不受管理的资源。
Dispose()
using(...) {}