Dispose
方法主要用于释放非托管资源。 处理
IDisposable
实现的实例成员时,通常会级联
Dispose
调用。 实现
Dispose
有其他原因,例如,为了释放已分配的内存、删除已添加到集合中的项,或发出释放已获取的锁的信号。
.NET 垃圾回收器
不会分配或释放非托管内存。 对象释放模式(称为“释放模式”)会对对象生存期强制施加顺序。 释放模式用于实现
IDisposable
接口的对象。 在与文件和管道句柄、注册表句柄、等待句柄或指向非托管内存块的指针交互时,此模式很常见,因为垃圾回收器无法回收非托管对象。
若要帮助确保始终适当地清理资源,
Dispose
方法应为幂等,这样可以多次调用而不引发异常。 此外,
Dispose
的后续调用不应执行任何操作。
为
GC.KeepAlive
方法提供的代码示例演示了垃圾回收如何引起终结器运行,而对该对象或其成员的非托管引用仍在使用中。 利用
GC.KeepAlive
使对象从当前例程开始到调用此方法的那一刻为止都不适合进行垃圾回收,这是可行的。
对于依赖关系注入,在
IServiceCollection
中注册服务时,会代表你隐式管理
IServiceCollection
。
IServiceProvider
和相应的
IHost
协调资源清理。 具体而言,
IDisposable
和
IAsyncDisposable
的实现在其指定生存期结束时正确释放。
有关详细信息,请参阅
.NET 中的依赖关系注入
。
编写对象终结器的代码是一项复杂的任务,如果处理不好可能会出现问题。 因此,建议你构造
System.Runtime.InteropServices.SafeHandle
对象,而非实现终结器。
System.Runtime.InteropServices.SafeHandle
是一种抽象托管类型,该类型包装了可标识非托管资源的
System.IntPtr
。 在 Windows 上,它可能标识一个句柄,而在 Unix 上则可能标识一个文件描述符。
SafeHandle
提供了所有必要的逻辑,以确保在处理
SafeHandle
或删除对
SafeHandle
的所有引用并最终完成
SafeHandle
实例时,只释放该资源一次。
System.Runtime.InteropServices.SafeHandle
是抽象基类。 派生类会为不同类型的句柄提供特定实例。 这些派生类可验证
System.IntPtr
的哪些值被视为无效,以及如何实际释放句柄。 例如,
SafeFileHandle
派生自
SafeHandle
以包装可标识打开的文件句柄/描述符的
IntPtrs
,并重写其
SafeHandle.ReleaseHandle()
方法来关闭它(通过 Unix 上的
close
函数或 Windows 上的
CloseHandle
函数)。 .NET 库中创建非托管资源的大多数 API 会将其包装在
SafeHandle
中,并根据需要返回此
SafeHandle
,而不是返回原始指针。 在与非托管组件进行交互并获取非托管资源的
IntPtr
的情况下,你可以创建自己的
SafeHandle
类型进行包装。 因此,极少数非
SafeHandle
类型需要实现终结器。 大多数可释放模式实现最终只包装其他受管理资源,其中某些资源可能是
SafeHandle
对象。
Microsoft.Win32.SafeHandles
命名空间中的以下派生类提供安全句柄。
它保存的资源
Dispose() 和 Dispose(bool)
IDisposable
接口需要实现单个无参数的方法
Dispose
。 此外,任何非密封类都应具有
Dispose(bool)
重载方法。
方法签名为:
public
非虚拟的(Visual Basic 中的
NotOverridable
)(
IDisposable.Dispose
实现)。
protected virtual
(在 Visual Basic 中为
Overridable
)
Dispose(bool)
。
Dispose() 方法
由于
public
、非虚拟(Visual Basic 中为
NotOverridable
)、无参数的
Dispose
方法在不再需要时(由该类型的使用者)调用,因此其用途是释放非托管资源,执行常规清理,以及指示终结器(如果存在)不必运行。 释放与托管对象关联的实际内存始终是
垃圾回收器
的域。 因此,它具有标准实现:
public void Dispose()
// Dispose of unmanaged resources.
Dispose(true);
// Suppress finalization.
GC.SuppressFinalize(this);
Public Sub Dispose() _
Implements IDisposable.Dispose
' Dispose of unmanaged resources.
Dispose(True)
' Suppress finalization.
GC.SuppressFinalize(Me)
End Sub
Dispose
方法执行所有对象清理,使垃圾回收器不再需要调用对象的
Object.Finalize
重写。 因此,调用
SuppressFinalize
方法会阻止垃圾回收器运行终结器。 如果类型没有终结器,则对
GC.SuppressFinalize
的调用不起作用。 实际的清除由
Dispose(bool)
方法重载执行。
Dispose(bool) 方法重载
在重载中,
disposing
参数是一个
Boolean
,它指示方法调用是来自
Dispose
方法(其值为
true
)还是来自终结器(其值为
false
)。
protected virtual void Dispose(bool disposing)
if (_disposed)
return;
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.
_disposed = true;
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then Exit Sub
' A block that frees unmanaged resources.
If disposing Then
' Deterministic call…
' A conditional block that frees managed resources.
End If
disposed = True
End Sub
从终结器调用时,
disposing
参数应为
false
,从
IDisposable.Dispose
方法调用时应为
true
。 换言之,确定情况下调用时为
true
,而在不确定情况下调用时为
false
。
方法的主体包含三个代码块:
如果对象已释放,则为条件返回块。
释放非托管资源的块。 无论
disposing
参数的值如何,都会执行此块。
释放托管资源的条件块。 如果
disposing
的值为
true
,则执行此块。 它释放的托管资源可包括:
实现
IDisposable
的托管对象。
可用于调用其
Dispose
实现(级联释放)的条件块。 如果你已使用
System.Runtime.InteropServices.SafeHandle
的派生类来包装非托管资源,则应在此处调用
SafeHandle.Dispose()
实现。
占用大量内存或使用短缺资源的托管对象。
将大型托管对象引用分配到
null
,使它们更有可能无法访问。 相比以非确定性方式回收它们,这样做释放的速度更快。
如果方法调用来自终结器,则应仅执行释放非托管资源的代码。 实施者负责确保假路径不会与可能已被释放的托管对象交互。 这一点很重要,因为垃圾回收器在终止期间释放托管对象的顺序是不确定的。
级联释放调用
如果你的类拥有一个字段或属性,并且其类型实现
IDisposable
,则包含类本身还应实现
IDisposable
。 实例化
IDisposable
实现并将其存储为实例成员的类,也负责清理。 这可帮助确保引用的可释放类型可通过
Dispose
方法明确执行清理。 在下面的示例中,类为
sealed
(Visual Basic 中为
NotInheritable
)。
using System;
public sealed class Foo : IDisposable
private readonly IDisposable _bar;
public Foo()
_bar = new Bar();
public void Dispose() => _bar.Dispose();
Public NotInheritable Class Foo
Implements IDisposable
Private ReadOnly _bar As IDisposable
Public Sub New()
_bar = New Bar()
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
_bar.Dispose()
End Sub
End Class
如果类具有
IDisposable
字段或属性但不拥有它,这意味着该类不会创建对象,则该类不需要实现
IDisposable
。
在某些情况下,你可能希望在终结器(包括终结器调用的
Dispose(false)
方法)中执行
null
检查。 主要原因之一是不确定实例是否已完全初始化(例如,构造函数中可能会引发异常)。
实现释放模式
所有非密封类(或未修改为
NotInheritable
的 Visual Basic 类)都应被视为潜在的基类,因为它们可以被继承。 如果为任何潜在基类实现释放模式,则必须提供以下内容:
调用
Dispose
方法的
Dispose(bool)
实现。
执行实际清理的
Dispose(bool)
方法。
从包装非托管资源的
SafeHandle
派生的类(推荐),或对
Object.Finalize
方法的重写。
SafeHandle
类提供了终结器,因此你无需自行编写。
基类可以只引用托管对象,并实现释放模式。 在这些情况下,不需要终结器。 仅当直接引用非托管资源时,才需要终结器。
这里有一个常规的例子,它实现了使用安全句柄的基类的释放模式。
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
public class BaseClassWithSafeHandle : IDisposable
// To detect redundant calls
private bool _disposedValue;
// Instantiate a SafeHandle instance.
private SafeHandle? _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
Dispose(true);
GC.SuppressFinalize(this);
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
if (!_disposedValue)
if (disposing)
_safeHandle?.Dispose();
_safeHandle = null;
_disposedValue = true;
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
Public Class BaseClassWithSafeHandle
Implements IDisposable
' To detect redundant calls
Private _disposedValue As Boolean
' Instantiate a SafeHandle instance.
Private _safeHandle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not _disposedValue Then
If disposing Then
_safeHandle?.Dispose()
_safeHandle = Nothing
End If
_disposedValue = True
End If
End Sub
End Class
上一个示例使用
SafeFileHandle
对象阐释模式;可以使用派生自
SafeHandle
的任何对象来替代。 请注意,该示例不会正确实例化其
SafeFileHandle
对象。
以下是一个常规模式,用于实现重写
Object.Finalize
的基类的释放模式。
using System;
public class BaseClassWithFinalizer : IDisposable
// To detect redundant calls
private bool _disposedValue;
~BaseClassWithFinalizer() => Dispose(false);
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
Dispose(true);
GC.SuppressFinalize(this);
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
if (!_disposedValue)
if (disposing)
// TODO: dispose managed state (managed objects)
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
_disposedValue = true;
Public Class BaseClassWithFinalizer
Implements IDisposable
' To detect redundant calls
Private _disposedValue As Boolean
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not _disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects)
End If
' TODO free unmanaged resources (unmanaged objects) And override finalizer
' TODO: set large fields to null
_disposedValue = True
End If
End Sub
End Class
在 C# 中,通过提供
终结器
而不是重写
Object.Finalize
来实现终结。 在 Visual Basic 中,将使用
Protected Overrides Sub Finalize()
创建一个终结器。
实现派生类的释放模式
从实现
IDisposable
接口的类派生的类不应实现
IDisposable
,因为
IDisposable.Dispose
的基类实现由其派生类继承。 若要清理派生类,请提供以下内容:
protected override void Dispose(bool)
方法,用于替代基类方法并执行派生类的实际清理。 此方法还必须调用
base.Dispose(bool)
(Visual Basic 中的
MyBase.Dispose(bool)
)方法,并将释放状态(
bool disposing
参数)作为参数传递给它。
从包装非托管资源的
SafeHandle
派生的类(推荐),或对
Object.Finalize
方法的重写。
SafeHandle
类提供了一个使你无需编写代码的终结器。 如果你提供了终结器,它必须调用具有
false
参数的
Dispose(bool)
重载。
以下是一个常规模式的示例,该模式用于实现使用安全句柄的派生类的释放模式:
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
public class DerivedClassWithSafeHandle : BaseClassWithSafeHandle
// To detect redundant calls
private bool _disposedValue;
// Instantiate a SafeHandle instance.
private SafeHandle? _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
if (!_disposedValue)
if (disposing)
_safeHandle?.Dispose();
_safeHandle = null;
_disposedValue = true;
// Call base class implementation.
base.Dispose(disposing);
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices
Public Class DerivedClassWithSafeHandle
Inherits BaseClassWithSafeHandle
' To detect redundant calls
Private _disposedValue As Boolean
' Instantiate a SafeHandle instance.
Private _safeHandle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not _disposedValue Then
If disposing Then
_safeHandle?.Dispose()
_safeHandle = Nothing
End If
_disposedValue = True
End If
' Call base class implementation.
MyBase.Dispose(disposing)
End Sub
End Class
上一个示例使用
SafeFileHandle
对象阐释模式;可以使用派生自
SafeHandle
的任何对象来替代。 请注意,该示例不会正确实例化其
SafeFileHandle
对象。
以下是一个常规模式,用于实现重写
Object.Finalize
的派生类的释放模式:
public class DerivedClassWithFinalizer : BaseClassWithFinalizer
// To detect redundant calls
private bool _disposedValue;
~DerivedClassWithFinalizer() => Dispose(false);
// Protected implementation of Dispose pattern.
protected override 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;
// Call the base class implementation.
base.Dispose(disposing);
Public Class DerivedClassWithFinalizer
Inherits BaseClassWithFinalizer
' To detect redundant calls
Private _disposedValue As Boolean
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
' Protected implementation of Dispose pattern.
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not _disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects).
End If
' TODO free unmanaged resources (unmanaged objects) And override a finalizer below.
' TODO: set large fields to null.
_disposedValue = True
End If
' Call the base class implementation.
MyBase.Dispose(disposing)
End Sub
End Class
SuppressFinalize
IDisposable
IDisposable.Dispose
Microsoft.Win32.SafeHandles
System.Runtime.InteropServices.SafeHandle
Object.Finalize
定义和使用类和结构 (C++/CLI)
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:
https://aka.ms/ContentUserFeedback
。
提交和查看相关反馈