我试图从书本,互联网和堆栈溢出中找到我的问题的实际答案,但到目前为止没有任何帮助我,所以希望我能够准确地说出我的问题。
一般来说,我总是找到与如何释放内存相同的基本用法,即约。如下,我确实理解代码本身:
public class MyClass : IDisposable
{
bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Dispose(true);
GC.SuppressFinalize(this);
disposed = true;
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//free managed ressources
}
// free other ressources
}
~MyClass()
{
Dispose(false);
}
}
这对方法的工作方式完全有意义。但现在我的问题是:为什么我们需要基类IDisposable?在此代码示例中,我们定义了一个名为Dispose()
的方法。当我到处读到该方法是IDisposable的一部分时,我们刚刚在MyClass
中定义了该方法,如果我们没有实现基类IDisposable,或者我对这个假设错了,这个代码仍然可以工作吗?
我对C#并不是全新的,但我仍然需要学习很多东西,所以希望有人可以带领我朝着正确的方向前进。我检查了另一篇同样问题的帖子,但找不到它,所以如果它确实存在并且它确实回答了我的问题,请带我去那里,我将删除这篇文章。
答案 0 :(得分:7)
你是对的,因为你的析构函数~MyClass
调用Dispose
,似乎不需要接口IDisposable
。
但Dispose
不仅仅由析构函数调用。当您希望处理非托管资源时,可以在代码中自己调用它。这是必需的,因为你不知道什么时候调用析构函数(它取决于垃圾收集器)。
最后,当您使用IDisposable.Dispose
时,会调用using
。
using(MyDisposableClass myObject = new MyDisposableClass())
{
// My Code
}
相当于:
MyDisposableClass myObject = new MyDisposableClass();
try
{
// My Code
}
finally
{
myObject.Dispose();
}
答案 1 :(得分:2)
IDisposable.Dispose的实际实现调用Dispose(bool)的基类实现。任何从这个类继承的人现在都需要处理以下任务:
public override Dispose(bool disposing)
{
base.Dispose(disposing);
//my disposal code
}
使用这种公认的模式允许继承者扩展处理代码而不会破坏基类的处理。
通常情况下,如果您没有非托管资源来处置 AND 可以密封您的课程,您可以使用以下代码简化问题:
public sealed class SomeDisposable:IDisposable
{
public void Dispose()
{
//just go ahead and clean up
//because we're sealed, no-one can ever break
//this code via inheritance
}
//~SomeDisposable()
//{
// if this is being called then it will be called
// on all referenced and unrooted IDisposables too
// If everything is managed, that means we've got nothing
// left to clean up, so we can omit this Finalizer
//}
}
答案 2 :(得分:2)
实现IDispose为您提供了一个释放“拥有”资源的地方,如流,句柄或数据库连接。
从垃圾收集器中调用Dispose(),基本上询问对象:“如果有什么不再需要,但我无法弄明白;现在就释放它;清理!”
在某种意义上与C ++中的析构函数相当
区别在于,C ++析构函数会立即被调用,而Dispose()会被及时调用。
在大多数情况下,您不需要实现它。 GC非常聪明,可以在90%的情况下找出如何释放使用过的资源。
但是例如:释放流使用的内存不会自动关闭 流和释放数据库连接也不会关闭它。
实现Dispose允许您在释放对象时关闭文件:
internal class Something : IDisposable {
private Stream stream;
public void SomeMethod() {
stream.Write("nskdns");
}
public void Dispose() {
if (stream != null) {
stream.Close();
}
}
此外:实现IDispose使您有机会在using语句中使用该类:
public void Example() {
using (var x = new Something())
{
x.SomeMethod();
}
}
确保x在GC被释放时始终关闭已使用的流。
我更喜欢在类上使用专用的Close()方法来允许显式关闭流而不是依赖于GC并调用Dispose()
答案 3 :(得分:1)
它与C#编译器一起用于using
块。