为什么使用Dispose作为常规方法是不好的
本文关键字:方法 常规 Dispose 为什么 | 更新日期: 2023-09-27 18:18:32
试着弄清楚。有人告诉我
Dispose是而不是只是一个方法——它相当于其他语言中的析构函数。
Ok。Msdn对此也非常大声。
然后
class Test : IDisposable
{
public string Property { get; set; } = "Test";
public void Dispose() => Console.WriteLine("Disposed, very scary");
}
class Program
{
static void Main(string[] args)
{
var test = new Test();
test.Dispose();
test.Property = "123"; // but it's disposed OMG! do not do this!
test.Dispose();
using (var another = new Test())
for (int i = 0; i < 10; i++)
{
another.Dispose();
GC.Collect(); // or what should I call to make it crash?
}
Console.ReadKey();
}
}
没有任何问题。
我对Dispose
的看法:
- 它是一个普通的公共方法;
-
IDisposable
与using
配合使用可以自动调用Dispose
,仅此而已; - 如果对象状态得到适当的维护,在任何时候都可以在内部调用它。
如果我说错了请指正。
p。S: Downvote的意思是"问题不好/没用/有问题"。如果你只是不同意我的想法-发表评论或回答。它将对那些像我现在这样思考的人有用(因为我错了?
Dispose
只是一个方法,你可以像调用其他方法一样调用它。它总是通过IDisposable
接口暴露(是的,显然您可以将方法命名为Dispose
而不实现IDisposable
, 不要这样做!)。然而,手动调用有时是一种代码气味,可能应该使用using
代替的代码气味。这里的"手动"是指在另一个Dispose
的实现之外调用Dispose
。
调用它两次也应该是安全的,并且有文档记录:
如果一个对象的Dispose方法被调用了不止一次,该对象必须忽略第一次之后的所有调用。如果多次调用Dispose方法,对象不能抛出异常。 Dispose以外的实例方法可以在资源已经被处置时抛出ObjectDisposedException。
(我强调)
你应该调用Dispose
两次吗?不! 。这也是一种代码的味道,代码不再能够控制它已经做了什么,还有什么要做,最终做的事情"只是为了确定"。也不要这样做!
所以如果你写的代码正确,当然你可以手动调用Dispose
。
你是对的,Dispose只是另一个方法,属于IDisposable。它还有一个额外的好处,就是能够在using()作用域结束时自动调用——它不是等同于析构函数,告诉你这一点的人并不真正理解他们在说什么。
我总是在可能的情况下使用using()块,但如果你小心的话,你可以手动调用Dispose来代替,它会有同样的效果。
Visual Studio 2015提供了(最终)一个符合指南的IDisposable
实现建议模式。
这是VS在选择实现一次性模式时为你创建的存根。TODOs指导我们完成实现。
class Disposable : IDisposable
{
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: dispose managed state (managed objects).
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~Disposable() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
注意使用一个标志来指示Dispose
是否已经被调用。此标志可用于在类实现的方法调用和属性上抛出ObjectDisposedException
实例。
Dispose
的目的一直是清理非托管资源。然而,using
关键字的语法糖(需要一个IDisposable
)允许您创建真正整洁的"上下文"模式类来管理资源访问,即使没有使用非托管资源。
. net中的Dispose
与其他语言中的析构函数之间有一个关键的区别:如果一个人有一个指向另一种语言中的对象的指针,并且该对象被删除了,那么一个人将拥有一个无效的指针,并且没有办法对它做任何事情,包括确定它是否仍然有效,而不调用未定义行为。相比之下,在。net中,如果一个对象的引用获得了 Dispose
d,那么该引用将继续是对该对象的有效引用。对象可能会拒绝做很多事情,因为它已经被处理了,但这种拒绝是由对象本身肯定地产生的。无未定义行为。
Dispose
不是这样。因此,代码应该避免池化面向公共的对象,而是让每个对新对象的请求都返回一个新对象(可能是池化对象的包装器)。如果在包装器之外不存在对池对象的引用,并且Dispose
在将对象返回到池之前使该引用无效,则可以通过将池对象封装在新的包装器中来满足未来的对象请求,该包装器将再次保存对它的唯一引用。