zoukankan      html  css  js  c++  java
  • C# 中正确实现 IDisposable 接口

    作用

    此接口的主要用途是释放非托管资源。 当不再使用托管对象时,垃圾回收器会自动释放分配给该对象的内存。 但无法预测进行垃圾回收的时间。 另外,垃圾回收器对窗口句柄或打开的文件和流等非托管资源一无所知。

    检查

    在 Visual Studio 中运行代码分析的时候,如果某一个类中,包含了实现 IDisposable 模式的属性,则会提醒你该类同样需要实现 IDisposable 模式,而实现 IDisposable 模式是有一套固定的模式的。这种模式能更有效的防止内存泄漏,也能在某些地方更简洁的书写代码,比如 using 关键字就是专为此而生。

    using 关键字

    提供能确保正确使用 IDisposable 对象的方便语法。以下是示例:

    1. using (Font font = new Font("Arial", 10.0f)) {
    2. byte charset = font.GdiCharSet;
    3. }

    using 关键字保证在离开 using 作用域的时候一定会调用 font.Dispose 。所以,如果只是在局部使用了 IDisposable 变量,最好这样包起来,以防止内存泄漏。

    实现 IDisposable

    MSDN 提供了一套标准的实现模板,地址在这:CA1063: Implement IDisposable correctly,我稍微有一点修改的实现了自己的:

    1. /// <summary>
    2. /// @author Easily
    3. /// </summary>
    4. public class BaseObject : IDisposable {
    5. private bool _enabled = true;
    6. public bool enabled {
    7. get { return _enabled; }
    8. }
    9. public void Dispose() {
    10. if (_enabled) {
    11. Dispose(true);
    12. }
    13. }
    14. private void Dispose(bool value) {
    15. if (_enabled) {
    16. _enabled = false;
    17. Destroy();
    18. if (value) {
    19. GC.SuppressFinalize(this);
    20. }
    21. }
    22. }
    23. virtual protected void Destroy() {
    24. // release managed resource here
    25. }
    26. ~BaseObject() {
    27. Dispose(false);
    28. }
    29. }

    需要释放的资源会在 Destroy 里面得到释放,所以,子类如果有需要释放的资源,必须重写 DestroyDestroy 只会被调用一次,之后 enabled 属性会被设置为 false,如果子类在运行过程中正在调用异步的方法,回调必须检查 enabled 属性。

    并发版本实现

    以上的实现在并发环境下很容易出问题,并发的情况下,需要对 _enabled 锁定,使用 lock 关键字即可:

    1. lock (_lockObj) {
    2. _enabled = false;
    3. }

    所以,这就需要所有用到 _enabled 的地方都进行锁定,还有一个方法,使用 Interlocked 提供的原子操作,以下是并发版本:

    1. /// <summary>
    2. /// @author Easily
    3. /// </summary>
    4. public class BaseObject : IDisposable {
    5. private int _disposed;
    6. public void Dispose() {
    7. Dispose(true);
    8. GC.SuppressFinalize(this);
    9. }
    10. private void Dispose(bool disposing) {
    11. if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0) {
    12. return;
    13. }
    14. if (disposing) {
    15. Destroy();
    16. }
    17. }
    18. virtual protected void Destroy() {
    19. //
    20. }
    21. ~BaseObject() {
    22. Dispose(false);
    23. }
    24. }




  • 相关阅读:
    原生js实现 table表格列宽拖拽
    vue.js 利用SocketCluster实现动态添加数据及排序
    angular-websocket.js 使用
    判断当前页面是否是激活状态。
    remove ---会报错discard不会报错
    .pop ----remove 删除
    add添加
    #将相同值输出,取一个值
    集合
    __delattr__\__delitem__
  • 原文地址:https://www.cnblogs.com/yili16438/p/1179c32075631f6f6991ea672cf4ce06.html
Copyright © 2011-2022 走看看