正确实现IDisposable

时间:2013-08-20 13:53:20

标签: c# .net memory-management memory-leaks garbage-collection

在我的课程中,我按如下方式实现IDisposable:

public class User : IDisposable
{
    public int id { get; protected set; }
    public string name { get; protected set; }
    public string pass { get; protected set; }

    public User(int UserID)
    {
        id = UserID;
    }
    public User(string Username, string Password)
    {
        name = Username;
        pass = Password;
    }

    // Other functions go here...

    public void Dispose()
    {
        // Clear all property values that maybe have been set
        // when the class was instantiated
        id = 0;
        name = String.Empty;
        pass = String.Empty;
    }
}

在VS2012中,我的代码分析说要正确实现IDisposable,但我不确定我在这里做错了什么。
具体文字如下:

  

CA1063正确实施IDisposable在“用户”上提供Dispose(bool)的可覆盖实现,或将类型标记为已密封。对Dispose(false)的调用应该只清理本机资源。对Dispose(true)的调用应该清理托管和本机资源。 stman User.cs 10

供参考:CA1063: Implement IDisposable correctly

我已经阅读了这个页面,但我担心我真的不明白这里需要做些什么。

如果有人能用更多的术语解释问题是什么和/或IDisposable应该如何实施,那将真的有用!

8 个答案:

答案 0 :(得分:95)

这将是正确的实现,虽然我没有看到您需要在您发布的代码中处置任何内容。您只需在以下时间实施IDisposable

  1. 您拥有非托管资源
  2. 你坚持引用本身就是一次性的东西。
  3. 您发布的代码中没有任何内容需要处理。

    public class User : IDisposable
    {
        public int id { get; protected set; }
        public string name { get; protected set; }
        public string pass { get; protected set; }
    
        public User(int userID)
        {
            id = userID;
        }
        public User(string Username, string Password)
        {
            name = Username;
            pass = Password;
        }
    
        // Other functions go here...
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if (disposing) 
            {
                // free managed resources
            }
            // free native resources if there are any.
        }
    
    }
    

答案 1 :(得分:53)

首先,您不需要“清理”stringint - 它们将由垃圾收集器自动处理。 Dispose中唯一需要清理的是非托管资源或实施IDisposable的托管资源。

但是,假设这只是一个学习练习,推荐实现IDisposable的方法是添加“安全捕获”以确保任何资源不会被处理两次:

public void Dispose()
{
    Dispose(true);

    // Use SupressFinalize in case a subclass 
    // of this type implements a finalizer.
    GC.SuppressFinalize(this);   
}
protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing) 
        {
            // Clear all property values that maybe have been set
            // when the class was instantiated
            id = 0;
            name = String.Empty;
            pass = String.Empty;
        }

        // Indicate that the instance has been disposed.
        _disposed = true;   
    }
}

答案 2 :(得分:37)

以下示例显示了实现<rule name="Redirect to HTTPS" stopProcessing="true"> <match url="(.*)" /> <conditions> <add input="{HTTPS}" pattern="^OFF$" /> </conditions> <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther" /> </rule> 接口的一般最佳做法。 Reference

请记住,只有在类中有非托管资源时才需要析构函数(终结器)。如果添加析构函数,则应该在Dispose 中禁止Finalization,否则会导致对象驻留在内存中两个垃圾循环(注意:Read how Finalization works)。下面的例子详细阐述了上述内容。

IDisposable

答案 3 :(得分:13)

IDisposable的存在是为了清理垃圾收集器不会自动清理的非托管资源。

您正在“清理”的所有资源都是托管资源,因此您的Dispose方法无法完成任何操作。您的班级不应该实施IDisposable。垃圾收集器将自行处理所有这些字段。

答案 4 :(得分:12)

你需要像这样使用一次性模式

private bool _disposed = false;

protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing)
        {
            // Dispose any managed objects
            // ...
        }

        // Now disposed of any unmanaged objects
        // ...

        _disposed = true;
    }
}

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);  
}

// Destructor
~YourClassName()
{
    Dispose(false);
}

答案 5 :(得分:8)

由于类没有获取任何非托管资源(文件,数据库连接等),因此您无需将User类设为IDisposable 。通常,我们将类标记为 IDisposable如果他们至少有一个IDisposable字段或/和属性。   在实施IDisposable时,最好根据Microsoft的典型方案:

public class User: IDisposable {
  ...
  protected virtual void Dispose(Boolean disposing) {
    if (disposing) {
      // There's no need to set zero empty values to fields 
      // id = 0;
      // name = String.Empty;
      // pass = String.Empty;

      //TODO: free your true resources here (usually IDisposable fields)
    }
  }

  public void Dispose() {
    Dispose(true);

    GC.SuppressFinalize(this);
  } 
}

答案 6 :(得分:3)

只要您想要确定性(已确认)垃圾收集,就会实施Idisposable。

class Users : IDisposable
    {
        ~Users()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
            // This method will remove current object from garbage collector's queue 
            // and stop calling finilize method twice 
        }    

        public void Dispose(bool disposer)
        {
            if (disposer)
            {
                // dispose the managed objects
            }
            // dispose the unmanaged objects
        }
    }

创建和使用Users类时,使用&#34;使用&#34;阻止显式调用dispose方法:

using (Users _user = new Users())
            {
                // do user related work
            }

创建的using块的结束用户对象将通过dispose方法的隐式调用来处理。

答案 7 :(得分:0)

我看到了很多Microsoft Dispose模式的例子,这实际上是一种反模式。正如许多人指出的那样,问题中的代码根本不需要IDisposable。但是,如果您打算在哪里实现它,请不要使用Microsoft模式。更好的答案是遵循本文中的建议:

https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About

可能唯一有用的另一件事是抑制代码分析警告... https://docs.microsoft.com/en-us/visualstudio/code-quality/in-source-suppression-overview?view=vs-2017