C# 正确实现 IDisposable

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18336856/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:57:48  来源:igfitidea点击:

Implementing IDisposable correctly

c#.netmemory-managementmemory-leaksgarbage-collection

提问by Ortund

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.
The exact text is as follows:

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

CA1063 Implement IDisposable correctly Provide an overridable implementation of Dispose(bool) on 'User' or mark the type as sealed. A call to Dispose(false) should only clean up native resources. A call to Dispose(true) should clean up both managed and native resources. stman User.cs 10

CA1063 正确实现 IDisposable 在“用户”上提供可覆盖的 Dispose(bool) 实现或将类型标记为密封。调用 Dispose(false) 应该只清理本机资源。调用 Dispose(true) 应该清理托管资源和本机资源。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 lamens terms what the problem is and/or how IDisposable should be implemented, that will really help!

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

回答by Servy

IDisposableexists to provide a means for you to clean up unmanagedresources 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 Disposemethod is accomplishing nothing. Your class shouldn't implement IDisposableat all. The Garbage Collector will take care of all of those fields just fine on its own.

您正在“清理”的所有资源都是托管资源,因此您的Dispose方法一无所获。你的班级根本不应该实现IDisposable。垃圾收集器将自行处理所有这些字段。

回答by D Stanley

First of all, you don't need to "clean up" strings and ints - they will be taken care of automatically by the garbage collector. The only thing that needs to be cleaned up in Disposeare unmanaged resources or managed recources that implement IDisposable.

首先,您不需要“清理” strings 和ints - 它们将由垃圾收集器自动处理。唯一需要清理的Dispose是实现IDisposable.

However, assuming this is just a learning exercise, the recommendedway to implement IDisposableis 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;   
    }
}

回答by Belogix

You need to use the Disposable Patternlike 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);
}

回答by Daniel Mann

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 IDisposablewhen:

这将是正确的实现,尽管我在您发布的代码中没有看到您需要处理的任何内容。您只需要在以下情况下实施IDisposable

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

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

回答by Dmitry Bychenko

You have no need to do your Userclass being IDisposablesince the class doesn't acquireany non-managed resources (file, database connection, etc.). Usually, we mark classes as IDisposableif they have at least one IDisposablefield or/and property. When implementing IDisposable, better put it according Microsoft typical scheme:

由于该类不获取任何非托管资源(文件、数据库连接等),因此您无需执行User该类。通常,我们将类标记为 至少有一个字段或/和属性。在实现的时候,最好按照微软的典型方案来写:IDisposableIDisposableIDisposableIDisposable

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

回答by S.Roshanth

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 方法的隐式调用进行处理。

回答by CharithJ

The following example shows the general best practice to implement IDisposableinterface. Reference

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

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). Below example elaborate all above.

请记住,只有在类中有非托管资源时才需要析构函数(终结器)。如果你添加了一个析构函数,你应该在 Dispose 中取消 Finalization,否则它会导致你的对象在内存中驻留两个垃圾周期(注意:阅读 Finalization 是如何工作的)。下面的例子详细说明了以上所有内容。

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

回答by MikeJ

I see a lot of examples of the Microsoft Dispose pattern which is really an anti-pattern. As many have pointed out the code in the question does not require IDisposable at all. But if you where going to implement it please don't use the Microsoft pattern. Better answer would be following the suggestions in this article:

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

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年