加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

C# Dispose方法的实现 (释放资源)

(2012-08-16 09:07:45)
标签:

c

dispose()

资源释放

it

分类: c#

     C# Dispose方法的理解是什么呢?类型的Dispose方法应释放它拥有的所有资源。它还应该通过调用其父类型的Dispose方法释放其基类型拥有的所有资源。该父类型的 Dispose 方法应该释放它拥有的所有资源并同样也调用其父类型的 Dispose 方法,从而在整个基类型层次结构中传播此模式。若要确保始终正确地清理资源,Dispose 方法应该可以被多次调用而不引发任何异常。

Dispose 方法应该为它处置的对象调用 GC.SuppressFinalize 方法。如果对象当前在终止队列中,GC.SuppressFinalize 防止其 Finalize 方法被调用。请记住,执行 Finalize 方法会大大减损性能。如果您的 Dispose 方法已经完成了清理对象的工作,那么垃圾回收器就不必再调用对象的 Finalize 方法。

C# Dispose方法的实现时注意

为 System.GC.KeepAlive(System.Object) 方法提供的代码示例演示了强行垃圾回收如何在回收对象的成员仍在执行时引起终结器运行。在较长的Dispose方法末尾最好调用KeepAlive方法。

下面的代码示例旨在阐释用于为封装了非托管资源的类实现Dispose方法的建议设计模式。整个 .NET Framework 中都实现了此模式。

资源类通常是从复杂的本机类或 API 派生的,而且必须进行相应的自定义。使用这一代码模式作为创建资源类的一个起始点,并根据封装的资源提供必要的自定义。不能编译该示例,也不能将其直接用于应用程序。

在此示例中,基类 BaseResource 实现可由该类的用户调用的公共 Dispose 方法。而该方法又调用 virtual Dispose(bool disposing) 方法(Visual Basic 中为 virtual Dispose(disposing As Boolean))。根据调用方的标识传递 true 或 false。以虚 Dispose 方法为对象执行适当的清理代码。

Dispose(bool disposing) 以两种截然不同的方案执行。如果 disposing 等于 true,则该方法已由用户的代码直接调用或间接调用,并且可释放托管资源和非托管资源。如果 disposing 等于 false,则该方法已由运行库从终结器内部调用,并且只能释放非托管资源。因为终结器不会以任意特定的顺序执行,所以当对象正在执行其终止代码时,不应引用其他对象。如果正在执行的终结器引用了另一个已经终止的对象,则该正在执行的终结器将失败。

基类提供的 Finalize 方法或析构函数在未能调用 Dispose 的情况下充当防护措施。Finalize 方法调用带有参数的 Dispose 方法,同时传递 false。不应在 Finalize 方法内重新创建 Dispose 清理代码。调用 Dispose(false) 可以优化代码的可读性和可维护性。

类 MyResourceWrapper 阐释如何使用 Dispose 从实现资源管理的类派生。MyResourceWrapper 重写 virtual Dispose(bool disposing) 方法并为其创建的托管和非托管资源提供清理代码。MyResourceWrapper 还对其基类 BaseResource 调用 Dispose 以确保其基类能够适当地进行清理。请注意,派生类 MyResourceWrapper 没有不带参数的 Finalize 方法或 Dispose 方法,因为这两个方法从基类 BaseResource 继承这些参数。

C# Dispose方法的实现时注意

此示例中的 protected Dispose(bool disposing) 方法不强制线程安全,因为无法从用户线程和终结器线程同时调用该方法。另外,使用 BaseResource 的客户端应用程序应从不允许多个用户线程同时调用 protected Dispose(bool disposing) 方法。应用程序或类库的设计原则为:应用程序或类库应只允许一个线程拥有资源的生存期,并且应在不再需要资源时调用 Dispose。根据资源的不同,在处置资源时进行异步线程访问可能会带来安全风险。开发人员应仔细检查自己的代码,以确定最佳的方法来强制线程安全

C# Dispose方法的实现实例

  1. // Design pattern for the base class.
  2. // By implementing IDisposable, you are announcing that instances
  3. // of this type allocate scarce resources.
  4. public class BaseResource: IDisposable
  5. {
  6. // Pointer to an external unmanaged resource.
  7. private IntPtr handle;
  8. // Other managed resource this class uses.
  9. private Component Components;
  10. // Track whether Dispose has been called.
  11. private bool disposed = false;
  12. // Constructor for the BaseResource object.
  13. public BaseResource()
  14. {
  15. // Insert appropriate constructor code here.
  16. }
  17. // Implement IDisposable.
  18. // Do not make this method virtual.
  19. // A derived class should not be able to override this method.
  20. public void Dispose()
  21. {
  22. Dispose(true);
  23. // Take yourself off the Finalization queue
  24. // to prevent finalization code for this object
  25. // from executing a second time.
  26. GC.SuppressFinalize(this);
  27. }
  28. // Dispose(bool disposing) executes in two distinct scenarios.
  29. // If disposing equals true, the method has been called directly
  30. // or indirectly by a user's code. Managed and unmanaged resources
  31. // can be disposed.
  32. // If disposing equals false, the method has been called by the
  33. // runtime from inside the finalizer and you should not reference
  34. // other objects. Only unmanaged resources can be disposed.
  35. protected virtual void Dispose(bool disposing)
  36. {
  37. // Check to see if Dispose has already been called.
  38. if(!this.disposed)
  39. {
  40. // If disposing equals true, dispose all managed
  41. // and unmanaged resources.
  42. if(disposing)
  43. {
  44. // Dispose managed resources.
  45. Components.Dispose();
  46. }
  47. // Release unmanaged resources. If disposing is false,
  48. // only the following code is executed.
  49. CloseHandle(handle);
  50. handle = IntPtr.Zero;
  51. // Note that this is not thread safe.
  52. // Another thread could start disposing the object
  53. // after the managed resources are disposed,
  54. // but before the disposed flag is set to true.
  55. // If thread safety is necessary, it must be
  56. // implemented by the client.
  57. }
  58. disposed = true;
  59. }
  60. // Use C# destructor syntax for finalization code.
  61. // This destructor will run only if the Dispose method
  62. // does not get called.
  63. // It gives your base class the opportunity to finalize.
  64. // Do not provide destructors in types derived from this class.
  65. ~BaseResource()
  66. {
  67. // Do not re-create Dispose clean-up code here.
  68. // Calling Dispose(false) is optimal in terms of
  69. // readability and maintainability.
  70. Dispose(false);
  71. }
  72. // Allow your Dispose method to be called multiple times,
  73. // but throw an exception if the object has been disposed.
  74. // Whenever you do something with this class,
  75. // check to see if it has been disposed.
  76. public void DoSomething()
  77. {
  78. if(this.disposed)
  79. {
  80. throw new ObjectDisposedException();
  81. }
  82. }
  83. }
  84. // Design pattern for a derived class.
  85. // Note that this derived class inherently implements the
  86. // IDisposable interface because it is implemented in the base class.
  87. public class MyResourceWrapper: BaseResource
  88. {
  89. // A managed resource that you add in this derived class.
  90. private ManagedResource addedManaged;
  91. // A native unmanaged resource that you add in this derived class.
  92. private NativeResource addedNative;
  93. private bool disposed = false;
  94. // Constructor for this object.
  95. public MyResourceWrapper()
  96. {
  97. // Insert appropriate constructor code here.
  98. }
  99. protected override void Dispose(bool disposing)
  100. {
  101. if(!this.disposed)
  102. {
  103. try
  104. {
  105. if(disposing)
  106. {
  107. // Release the managed resources you added in
  108. // this derived class here.
  109. addedManaged.Dispose();
  110. }
  111. // Release the native unmanaged resources you added
  112. // in this derived class here.
  113. CloseHandle(addedNative);
  114. this.disposed = true;
  115. }
  116. finally
  117. {
  118. // Call Dispose on your base class.
  119. base.Dispose(disposing);
  120. }
  121. }
  122. }
  123. }
  124. // This derived class does not have a Finalize method
  125. // or a Dispose method without parameters because it inherits
  126. // them from the base class.

C# Dispose方法的实现以及C# Dispose方法的一些基本内容就向你介绍到这里,希望对你了解和学习C# Dispose方法有所帮助。

 

C#中垃圾收集器的出现意为着,通常不需要担心不再需要的对象,只要让这些对象的所有引用都超出作用域,并允许垃圾收集器在需要时释放资源即可。但是,垃圾收集器不知道如何释放未托管的资源(例如文件句柄、网络链接和数据库链接)。托管类在封装对未托管资源的直接或间接引用时,需要制定专门的规则,确保未托管资源在回收类的一个实例时释放。
在定义一个类时,可以使用两种机制来自动释放未托管资源。这些机制常常放在一起实现,因为每个机制都为问题解决提供了不同的解决方法。这两种机制是:
声明一个析构函数,作为类的一个成员
在类中实现System.IDisposable接口

实现IDisposable接口和析构函数

利用运行库强制执行的析构函数,但析构函数的执行是不确定的,而且,由于垃圾收集器的工作方式,它会给运行库增加不可接受的系统开销。
IDisposable接口提供了一种机制,允许类的用户控制释放资源的时间,但需要确保执行Dispose().

一般情况下,做好的的方法是执行这两种机制,获得这两种机制的有点,克服其缺点。

public class ResourceHolder : IDisposable
{
private bool isDispose = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (!isDispose)
{
if (disposing)
{
//Cleanup managed objects by calling their Dispose() methods
}
//Cleanup unmanaged objects
}
isDispose = true;
}

~ResourceHolder()
{
Dispose(false);
}
}

可以看出,Dispose()有第二个protected重载方法,它带一个bool参数,这是真正完成清理工作的方法。Dispose(bool)由析构函数和IDisposable.Dispose()调用。这个方法的重点是确保所有的清理代码都放在一个地方。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有