为什么将 Dispose 用作常规方法不好?
Why using Dispose as a normal method is bad?
正在想办法。有人告诉我
Dispose is not just a method - it's equivalent to a destructor in other languages.
好的。 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
:
- 这是一个正常的public方法;
IDisposable
配合using
有用,自动调用Dispose
,仅此而已;
- 如果对象状态得到适当维护,可以随时在内部调用任何代码。
如有错误请指正
P.S:投反对票意味着 "question is bad/not useful/has problem"。如果您只是不同意我的想法 - post 评论或回答。对和我现在想法一样的人会有用(因为我错了?然后证明)
没错,Dispose只是IDisposable的另一个方法。它只是有一个额外的好处,就是在 using() 作用域结束时能够自动调用 - 它 not 等同于析构函数,无论谁告诉你这并不真正理解他们的意思正在说。
我总是在可能的情况下使用 using() 块,但如果你小心的话,你可以手动调用 Dispose,它会产生相同的效果。
Dispose
只是一个方法,您可以像调用任何其他方法一样调用它。它总是通过 IDisposable
接口公开(是的,显然你可以命名一个方法 Dispose
而无需实现 IDisposable
,不要那样做! ).
但是,手动调用它 有时 代码味道,可能 应该使用 using
的代码味道.这里的 "manually" 是指在另一个 Dispose
.
的实现之外调用 Dispose
调用两次应该也是安全的 documented:
If an object's Dispose method is called more than once, the object must ignore all calls after the first one. The object must not throw an exception if its Dispose method is called multiple times. Instance methods other than Dispose can throw an ObjectDisposedException when resources are already disposed.
(我的重点)
你应该打电话给 Dispose
两次吗? 不!。这也是一种代码的代码味道,不再控制它已经完成的事情和剩下要做的事情并最终做事 "just to be sure"。 也不要那样做!
所以如果你写的代码正确,肯定可以手动调用Dispose
。
Visual Studio 2015 年(最终)提供了一个与指南相符的实施 IDisposable
的建议模式。
这是 VS 在选择实现 disposable 模式时为您创建的存根。 TODO 指导我们完成实施。
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
)可以让您创建非常整洁的 'context' 模式 类 来管理资源访问,即使没有非托管资源使用过。
像往常一样,清楚地记录用法和意图,你不会出错,但如果你不实现接口,请避免使用名为 'Dispose' 的方法。
.NET 中的 Dispose
与其他语言中的析构函数之间存在一个关键区别:如果一个指针指向另一种语言中的对象并且该对象被删除,那么将有一个 invalid 指针并且没有办法对它做任何事情,包括确定它是否仍然有效,而不调用未定义的行为。相比之下,在 .NET 中,如果一个对象的引用获得 Dispose
d,则该引用将继续是对相关对象的有效引用。该对象可能会拒绝做很多事情,因为它已被处置,但这种拒绝肯定是由对象本身产生的。不涉及未定义的行为。
另一方面,当在其他语言(如 C++)中调用析构函数时,对象可以确定不再存在指向它的有效指针,但 Dispose
并非如此。因此,代码应该避免池化 public 面向对象,而是让每个对新对象的请求 return 一个新对象(它可能是池化对象的包装器)。如果在包装器之外不存在对池对象的引用,并且 Dispose
在将对象放入池之前 Dispose
使该引用无效,则可以通过将池对象封装在一个新的对象中来满足未来的对象请求包装器将再次持有对它的唯一引用。
正在想办法。有人告诉我
Dispose is not just a method - it's equivalent to a destructor in other languages.
好的。 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
:
- 这是一个正常的public方法;
IDisposable
配合using
有用,自动调用Dispose
,仅此而已;- 如果对象状态得到适当维护,可以随时在内部调用任何代码。
如有错误请指正
P.S:投反对票意味着 "question is bad/not useful/has problem"。如果您只是不同意我的想法 - post 评论或回答。对和我现在想法一样的人会有用(因为我错了?然后证明)
没错,Dispose只是IDisposable的另一个方法。它只是有一个额外的好处,就是在 using() 作用域结束时能够自动调用 - 它 not 等同于析构函数,无论谁告诉你这并不真正理解他们的意思正在说。
我总是在可能的情况下使用 using() 块,但如果你小心的话,你可以手动调用 Dispose,它会产生相同的效果。
Dispose
只是一个方法,您可以像调用任何其他方法一样调用它。它总是通过 IDisposable
接口公开(是的,显然你可以命名一个方法 Dispose
而无需实现 IDisposable
,不要那样做! ).
但是,手动调用它 有时 代码味道,可能 应该使用 using
的代码味道.这里的 "manually" 是指在另一个 Dispose
.
Dispose
调用两次应该也是安全的 documented:
If an object's Dispose method is called more than once, the object must ignore all calls after the first one. The object must not throw an exception if its Dispose method is called multiple times. Instance methods other than Dispose can throw an ObjectDisposedException when resources are already disposed.
(我的重点)
你应该打电话给 Dispose
两次吗? 不!。这也是一种代码的代码味道,不再控制它已经完成的事情和剩下要做的事情并最终做事 "just to be sure"。 也不要那样做!
所以如果你写的代码正确,肯定可以手动调用Dispose
。
Visual Studio 2015 年(最终)提供了一个与指南相符的实施 IDisposable
的建议模式。
这是 VS 在选择实现 disposable 模式时为您创建的存根。 TODO 指导我们完成实施。
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
)可以让您创建非常整洁的 'context' 模式 类 来管理资源访问,即使没有非托管资源使用过。
像往常一样,清楚地记录用法和意图,你不会出错,但如果你不实现接口,请避免使用名为 'Dispose' 的方法。
.NET 中的 Dispose
与其他语言中的析构函数之间存在一个关键区别:如果一个指针指向另一种语言中的对象并且该对象被删除,那么将有一个 invalid 指针并且没有办法对它做任何事情,包括确定它是否仍然有效,而不调用未定义的行为。相比之下,在 .NET 中,如果一个对象的引用获得 Dispose
d,则该引用将继续是对相关对象的有效引用。该对象可能会拒绝做很多事情,因为它已被处置,但这种拒绝肯定是由对象本身产生的。不涉及未定义的行为。
另一方面,当在其他语言(如 C++)中调用析构函数时,对象可以确定不再存在指向它的有效指针,但 Dispose
并非如此。因此,代码应该避免池化 public 面向对象,而是让每个对新对象的请求 return 一个新对象(它可能是池化对象的包装器)。如果在包装器之外不存在对池对象的引用,并且 Dispose
在将对象放入池之前 Dispose
使该引用无效,则可以通过将池对象封装在一个新的对象中来满足未来的对象请求包装器将再次持有对它的唯一引用。