.net 正确实现IDisposable

kt06eoxx  于 2022-12-20  发布在  .NET
关注(0)|答案(8)|浏览(204)

在我的类中,我实现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在"User"上提供Dispose(bool)的可重写实现或将类型标记为密封。调用Dispose(false)应仅清除本机资源。调用Dispose(true)应同时清除托管资源和本机资源。stman User.cs 10
供参考:CA1063: Implement IDisposable correctly
我已经通读了这一页,但恐怕我真的不明白这里需要做些什么。
如果有人能用更外行的术语解释问题所在和/或IDisposable应该如何实现,那将非常有帮助!

bhmjp9jg

bhmjp9jg1#

这是正确的实现,尽管我在你发布的代码中没有看到任何需要处理的东西。你只需要在以下情况下实现IDisposable
1.您拥有非托管资源
1.你一直在引用那些本身就是一次性的东西。
您发布的代码中没有任何内容需要释放。

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.
    }
}
t0ybt7op

t0ybt7op2#

首先,你不需要“清理”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;   
    }
}
gzszwxb4

gzszwxb43#

以下示例显示了实现IDisposable接口的一般最佳实践。Reference

请记住,只有当类中有非托管资源时,才需要析构函数(终结器)。如果添加析构函数,则应在Dispose中取消Finalization,否则将导致对象在内存中驻留的时间比它应该驻留的时间长(注意:Read how Finalization works)。下面的例子详细说明了以上所有内容。

public class DisposeExample
{
    // A base class that implements IDisposable. 
    // By implementing IDisposable, you are announcing that 
    // instances of this type allocate scarce resources. 
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource. 
        private IntPtr handle;
        // Other managed resource this class uses. 
        private Component component = new Component();
        // Track whether Dispose has been called. 
        private bool disposed = false;

        // The class constructor. 
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable. 
        // Do not make this method virtual. 
        // A derived class should not be able to override this method. 
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method. 
            // Therefore, you should call GC.SupressFinalize to 
            // take this object off the finalization queue 
            // and prevent finalization code for this object 
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios. 
        // If disposing equals true, the method has been called directly 
        // or indirectly by a user's code. Managed and unmanaged resources 
        // can be disposed. 
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed. 
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up 
                // unmanaged resources here. 
                // If disposing is false, 
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;

            }
        }

        // Use interop to call the method necessary 
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# destructor syntax for finalization code. 
        // This destructor will run only if the Dispose method 
        // does not get called. 
        // It gives your base class the opportunity to finalize. 
        // Do not provide destructors in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here. 
            // Calling Dispose(false) is optimal in terms of 
            // readability and maintainability.
            Dispose(false);
        }
    }
    public static void Main()
    {
        // Insert code here to create 
        // and use the MyResource object.
    }
}
at0kjp5o

at0kjp5o4#

IDisposable的存在为您提供了一种清理 unmanaged 资源的方法,这些资源不会被垃圾收集器自动清理。
所有你正在清理的资源都是托管资源,因此你的Dispose方法什么也做不了。你的类根本不应该实现IDisposable。垃圾收集器会自己处理好所有这些字段。

puruo6ea

puruo6ea5#

您需要按如下方式使用一次性模式

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);
}
luaexgnf

luaexgnf6#

你不需要把你的User类做为IDisposable,因为类 * 不获取 * 任何非托管资源(文件、数据库连接等)。通常,如果类至少有一个IDisposable字段或/和属性,我们就把类标记为IDisposable。在实现IDisposable时,最好按照微软的典型方案来放置:

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);
  } 
}
uplii1fm

uplii1fm7#

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类时,使用“using”块以避免显式调用dispose方法:

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

using块创建的Users对象的结尾将通过dispose方法的隐式调用来释放。

wf82jlnq

wf82jlnq8#

我看到了很多Microsoft Dispose模式的例子,它实际上是一个反模式。正如许多人指出的,问题中的代码根本不需要IDisposable。但是如果你要实现它,请不要使用Microsoft模式。更好的答案是遵循本文中的建议:
https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About
另外唯一可能有用的方法是取消代码分析警告... https://learn.microsoft.com/en-us/visualstudio/code-quality/in-source-suppression-overview?view=vs-2017

相关问题