Dispose、Finalize、SuppressFinalize 方法
Dispose, Finalize, SuppressFinalize methods
我可以在同一个 class 中实现这两种方法吗?
public class MyClass : IDisposable
{
// some implementation
// if i missed to call Dispose() method;
~MyClass()
{
// it means, clear all does not mananage resources
// but dont use Dispose() method
}
public void Dispose()
{
// clear resources
// if i call this method will i can do this:
GC.SuppressFinalize()
// it means dont use Finalizw method for this object
}
}
我说的对吗?因为我无法理解这个 GC.SuppressFinalize() 方法?
是的,您可以实现这两种方法。
通常,如果对象可以同时具有托管和非托管引用,则正确的模式是:
public class MyClass : IDisposable
{
~MyClass()
{
Dispose(false);
}
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
public virtual void Dispose(bool disposing)
{
if(disposing)
{
// clear MANAGED references
}
// free UNMANAGED resources
}
}
但是您可以根据需要实现它。这只是一个模式。例如,如果您没有任何非托管资源并且您的 class 是密封的(因此您可以确定它永远不会使用任何非托管资源),您可以像这样实现它:
public sealed class MyClass : IDisposable
{
public void Dispose()
{
// release managed references
}
}
忘记终结器。
在第一个模式中,GC.SuppresFinalize(this)
正在做的是告诉垃圾收集器它不应该在释放对象时调用终结器(~MyClass()
方法):如果您已经明确调用Dispose()
那么您 已经 调用了您的虚拟 Dispose(bool)
函数,那么为什么还要调用它呢?
问题是 C# 中的终结器本身是不确定的:你不知道它什么时候会被调用......你甚至不能保证它会被调用(尽管如果之前没有调用它,它将在正常清理期间执行),这就是 IDisposable
存在的原因,它是 确定性地 释放托管引用的一种方式持有你的对象,并释放和释放它分配的非托管资源。
如果一个对象被 GC 释放,它持有的所有托管引用也将被释放,因此在调用终结器时无需清除 托管 引用.
但是您的应用程序应该尽最大努力释放它拥有的任何非托管资源。
如果您忘记了 Dispose()
,应该有最后一次释放它们的机会(当 GC 收集对象时,或者在应用程序运行时的最终清理时)。这就是为什么在正常模式下你还实现了一个终结器,并告诉它清理非托管资源如果你之前没有做过
请注意,与流行的看法相反,对 Dispose()
的调用没什么特别的,它只是一个方法调用:如果需要,您可以将其称为 FreeMyObject()
或 FooBar()
.它不会让垃圾收集器释放任何内存。使用 IDisposable
有一个 模式 ,如此重要以至于它获得了自己的语言语法结构(using
块),但仅此而已,一个模式。你可以做 Dispose()
做的同样的事情,而不用完全实现 IDisposable
。
我可以在同一个 class 中实现这两种方法吗?
public class MyClass : IDisposable
{
// some implementation
// if i missed to call Dispose() method;
~MyClass()
{
// it means, clear all does not mananage resources
// but dont use Dispose() method
}
public void Dispose()
{
// clear resources
// if i call this method will i can do this:
GC.SuppressFinalize()
// it means dont use Finalizw method for this object
}
}
我说的对吗?因为我无法理解这个 GC.SuppressFinalize() 方法?
是的,您可以实现这两种方法。
通常,如果对象可以同时具有托管和非托管引用,则正确的模式是:
public class MyClass : IDisposable
{
~MyClass()
{
Dispose(false);
}
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
public virtual void Dispose(bool disposing)
{
if(disposing)
{
// clear MANAGED references
}
// free UNMANAGED resources
}
}
但是您可以根据需要实现它。这只是一个模式。例如,如果您没有任何非托管资源并且您的 class 是密封的(因此您可以确定它永远不会使用任何非托管资源),您可以像这样实现它:
public sealed class MyClass : IDisposable
{
public void Dispose()
{
// release managed references
}
}
忘记终结器。
在第一个模式中,GC.SuppresFinalize(this)
正在做的是告诉垃圾收集器它不应该在释放对象时调用终结器(~MyClass()
方法):如果您已经明确调用Dispose()
那么您 已经 调用了您的虚拟 Dispose(bool)
函数,那么为什么还要调用它呢?
问题是 C# 中的终结器本身是不确定的:你不知道它什么时候会被调用......你甚至不能保证它会被调用(尽管如果之前没有调用它,它将在正常清理期间执行),这就是 IDisposable
存在的原因,它是 确定性地 释放托管引用的一种方式持有你的对象,并释放和释放它分配的非托管资源。
如果一个对象被 GC 释放,它持有的所有托管引用也将被释放,因此在调用终结器时无需清除 托管 引用.
但是您的应用程序应该尽最大努力释放它拥有的任何非托管资源。
如果您忘记了 Dispose()
,应该有最后一次释放它们的机会(当 GC 收集对象时,或者在应用程序运行时的最终清理时)。这就是为什么在正常模式下你还实现了一个终结器,并告诉它清理非托管资源如果你之前没有做过
请注意,与流行的看法相反,对 Dispose()
的调用没什么特别的,它只是一个方法调用:如果需要,您可以将其称为 FreeMyObject()
或 FooBar()
.它不会让垃圾收集器释放任何内存。使用 IDisposable
有一个 模式 ,如此重要以至于它获得了自己的语言语法结构(using
块),但仅此而已,一个模式。你可以做 Dispose()
做的同样的事情,而不用完全实现 IDisposable
。