简体   繁体   English

正确实现 IDisposable

[英]Implementing IDisposable correctly

In my classes I implement IDisposable as follows:在我的课程中,我按如下方式实现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;
    }
}

In VS2012, my Code Analysis says to implement IDisposable correctly, but I'm not sure what I've done wrong here.在 VS2012 中,我的代码分析说要正确实现 IDisposable,但我不确定我在这里做错了什么。
The exact text is as follows:确切的文字如下:

CA1063 Implement IDisposable correctly Provide an overridable implementation of Dispose(bool) on 'User' or mark the type as sealed. CA1063 正确实现 IDisposable 在“用户”上提供可覆盖的 Dispose(bool) 实现或将类型标记为密封。 A call to Dispose(false) should only clean up native resources.调用 Dispose(false) 应该只清理本机资源。 A call to Dispose(true) should clean up both managed and native resources.调用 Dispose(true) 应该清理托管资源和本机资源。 stman User.cs 10 stman 用户.cs 10

For reference: CA1063: Implement IDisposable correctly供参考: CA1063:正确实施 IDisposable

I've read through this page, but I'm afraid I don't really understand what needs to be done here.我已经通读了这个页面,但恐怕我真的不明白这里需要做什么。

If anyone can explain in more layman's terms what the problem is and/or how IDisposable should be implemented, that will really help!如果有人可以更通俗地解释问题是什么和/或应该如何实施IDisposable ,那真的很有帮助!

This would be the correct implementation, although I don't see anything you need to dispose in the code you posted.这将是正确的实现,尽管我在您发布的代码中没有看到您需要处理的任何内容。 You only need to implement IDisposable when:您只需要在以下情况下实施IDisposable

  1. You have unmanaged resources您拥有非托管资源
  2. You're holding on to references of things that are themselves disposable.你坚持引用本身是一次性的东西。

Nothing in the code you posted needs to be disposed.您发布的代码中没有任何内容需要处理。

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

First of all, you don't need to "clean up" string s and int s - they will be taken care of automatically by the garbage collector.首先,您不需要“清理” string s 和int s - 它们将由垃圾收集器自动处理。 The only thing that needs to be cleaned up in Dispose are unmanaged resources or managed recources that implement IDisposable .Dispose中唯一需要清理的是实现IDisposable非托管资源或托管资源。

However, assuming this is just a learning exercise, the recommended way to implement IDisposable is to add a "safety catch" to ensure that any resources aren't disposed of twice:然而,假设这只是一个学习练习,推荐的实现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;   
    }
}

The following example shows the general best practice to implement IDisposable interface.以下示例显示了实现IDisposable接口的一般最佳实践。 Reference 参考

Keep in mind that you need a destructor(finalizer) only if you have unmanaged resources in your class.请记住,只有在类中有非托管资源时才需要析构函数(终结器)。 And if you add a destructor you should suppress Finalization in the Dispose , otherwise it will cause your objects resides in memory for two garbage cycles (Note: Read how Finalization works ).如果你添加了一个析构函数,你应该在 Dispose 中取消 Finalization ,否则它会导致你的对象在内存中驻留两个垃圾周期(注意: 阅读 Finalization 是如何工作的)。 Below example elaborate all above.下面的例子详细说明了以上所有内容。

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

IDisposable exists to provide a means for you to clean up unmanaged resources that won't be cleaned up automatically by the Garbage Collector. IDisposable存在为您提供一种清理垃圾收集器不会自动清理的非托管资源的方法。

All of the resources that you are "cleaning up" are managed resources, and as such your Dispose method is accomplishing nothing.您正在“清理”的所有资源都是托管资源,因此您的Dispose方法什么也没做。 Your class shouldn't implement IDisposable at all.您的课程根本不应该实现IDisposable The Garbage Collector will take care of all of those fields just fine on its own.垃圾收集器将自行处理所有这些字段。

You need to use the Disposable Pattern like this:您需要像这样使用一次性模式

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

You have no need to do your User class being IDisposable since the class doesn't acquire any non-managed resources (file, database connection, etc.).您无需将User类设置为IDisposable因为该类不会获取任何非托管资源(文件、数据库连接等)。 Usually, we mark classes as IDisposable if they have at least one IDisposable field or/and property.通常,如果类至少有一个IDisposable字段或/和属性,我们将它们标记为IDisposable When implementing IDisposable , better put it according Microsoft typical scheme:在实现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);
  } 
}

Idisposable is implement whenever you want a deterministic (confirmed) garbage collection.只要您想要确定性(已确认的)垃圾收集,就可以实现 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
        }
    }

When creating and using the Users class use "using" block to avoid explicitly calling dispose method:创建和使用 Users 类时,使用“using”块来避免显式调用 dispose 方法:

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

end of the using block created Users object will be disposed by implicit invoke of dispose method.在 using 块的末尾创建的 Users 对象将通过 dispose 方法的隐式调用进行处理。

I see a lot of examples of the Microsoft Dispose pattern which is really an anti-pattern.我看到很多 Microsoft Dispose 模式的例子,这确实是一种反模式。 As many have pointed out the code in the question does not require IDisposable at all.正如许多人指出的那样,问题中的代码根本不需要 IDisposable。 But if you where going to implement it please don't use the Microsoft pattern.但是,如果您要实施它,请不要使用 Microsoft 模式。 Better answer would be following the suggestions in this article:更好的答案是遵循本文中的建议:

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

The only other thing that would likely be helpful is suppressing that code analysis warning... https://docs.microsoft.com/en-us/visualstudio/code-quality/in-source-suppression-overview?view=vs-2017唯一可能有用的另一件事是抑制该代码分析警告...... https://docs.microsoft.com/en-us/visualstudio/code-quality/in-source-suppression-overview?view=vs- 2017年

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM