我认为以前没有问过这个问题。我对在密封类上实现IDisposable
的最佳方法有些困惑,具体来说,该密封类不继承自基类。 (也就是说,这是我的固定学期的“纯密封课程”。)
也许你们中的一些人同意我,因为实施IDisposable
的准则非常令人困惑。就是说,我想知道我打算实现IDisposable
的方式是充分且安全的。
我正在执行一些P / Invoke代码,它们从IntPtr
分配Marshal.AllocHGlobal
,自然,我想干净地处置我创建的非托管内存。所以我在想像这样的东西
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public sealed class MemBlock : IDisposable
{
IntPtr ptr;
int length;
MemBlock(int size)
{
ptr = Marshal.AllocHGlobal(size);
length = size;
}
public void Dispose()
{
if (ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
GC.SuppressFinalize(this);
}
}
~MemBlock()
{
Dispose();
}
}
我假设因为MemBlock
是完全密封的,并且从不衍生自另一个类,所以不需要实现virtual protected Dispose(bool disposing)
。
而且,终结器是否绝对必要?欢迎所有想法。
终结器是必需的,作为一种回退机制,如果您忘记调用Dispose
,最终可以释放不受管理的资源。
否,您不应该在virtual
类中声明sealed
方法。它根本不会编译。另外,不建议在protected
类中声明新的sealed
成员。
一个小的补充;在general情况下,常见的模式是使用Dispose(bool disposing)
方法,这样您就可以知道自己是否在Dispose
(有更多可用的东西)与finalizer(在这里您不应真正接触)任何其他连接的受管对象)。
例如:
public void Dispose() { Dispose(true); }
~MemBlock() { Dispose(false); }
void Dispose(bool disposing) { // would be protected virtual if not sealed
if(disposing) { // only run this logic when Dispose is called
GC.SuppressFinalize(this);
// and anything else that touches managed objects
}
if (ptr != IntPtr.Zero) {
Marshal.FreeHGlobal(ptr);
ptr = IntPtr.Zero;
}
}
对于密封类,此模式需要不遵循,意味着你应该只需实现您的终结器,用简单的方法处理(即〜T()(在C#中完成)和Dispose()。选择后一种路线时,代码仍应遵守以下有关准则实施定稿和处理逻辑。
所以是的,你应该很好。
您确实需要Mehrdad所述的终结器。如果要避免这种情况,可以查看SafeHandle。我没有足够的使用P / Invoke的经验来建议正确的用法。
您不能在密封的类中声明虚拟方法。此外,在密封类中声明受保护的成员也会向您发出编译器警告。因此,您已经正确实现了它。出于显而易见的原因,不必在终结器中调用GC.SuppressFinalize(this),但这不会造成损害。
处理非托管资源时,必须具有终结器,因为它们不会自动释放,因此必须在终结器中进行处理,并在对象被垃圾回收后被自动调用。