在我的课程中,我按如下方式实现 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
,那将真的很有帮助!
Dispose
中的所有代码吗?
SqlConnection
、FileStream
等)),您只需实施 IDispoable
。您不需要并且不应该如果您只有像这里这样的托管资源,请实施 IDisposable
。这是 IMO 代码分析的一个主要问题。它非常擅长检查愚蠢的小规则,但不不擅长检查概念错误。
这将是正确的实现,尽管我在您发布的代码中看不到您需要处理的任何内容。您只需在以下情况下实施 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()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
}
// free native resources if there are any.
}
}
首先,您不需要“清理”string
和 int
- 它们将由垃圾收集器自动处理。 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;
}
}
readonly
语义)
IDisposable
的约定是多次调用 Dispose
是无害的(它不能破坏对象或抛出异常)。记住对象已被释放主要是为了使不能在已释放对象上使用的方法可以提前抛出 ObjectDisposedException
(而不是在对包含的对象调用方法时,甚至导致意外的不同异常)。
以下示例显示了实现 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.
}
}
IDisposable
的存在为您提供了一种清理垃圾收集器不会自动清理的非托管资源的方法。
您“清理”的所有资源都是托管资源,因此您的 Dispose
方法没有任何作用。您的类根本不应该实现 IDisposable
。垃圾收集器将自行处理所有这些字段。
您需要像这样使用一次性模式:
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);
}
SafeHandle
(和子类型)取代。在托管资源的情况下,实施适当的处置变得更加简单;您可以将代码精简为 void Dispose()
方法的简单实现。
您无需将 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);
}
}
只要您想要确定性(已确认)垃圾收集,就可以实现 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 方法的隐式调用进行处置。
我看到很多 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
不定期副业成功案例分享
using(){ }
,但要做到这一点,您需要实现 IDisposable,所以总的来说,我更喜欢通过 usings 访问一个类,尤其是。如果我只需要一两个函数中的类using
块。如果您不需要一个类是一次性的,请不要实现它。它没有任何目的。using
块的语义确实倾向于在IDisposable
界面之外吸引人,不过。我想有不止一些滥用IDisposable
只是为了范围的目的。GC.SuppressFinalize(this);
是没有意义的。正如@mariozski 指出的那样,如果在using
块中未使用类,则终结器将有助于确保完全调用Dispose
。