System.IDisposable 接口
本文提供了此 API 参考文档的补充说明。
接口的主要 IDisposable 用途是释放非托管资源。 垃圾回收器会在不再使用该对象时自动释放分配给托管对象的内存。 但是,无法预测何时发生垃圾回收。 此外,垃圾回收器不了解非托管资源,例如窗口句柄或打开文件和流。
Dispose使用此接口的方法可以与垃圾回收器一起显式释放非托管资源。 当不再需要对象时,对象的使用者可以调用此方法。
警告
将接口添加到 IDisposable 现有类是一项重大更改。 由于类型预先存在的使用者无法调用 Dispose,因此无法确定将释放类型持有的非托管资源。
IDisposable.Dispose由于当不再需要实例拥有的资源时,由类型使用者调用实现,因此应将托管对象包装在(建议的替代项)中SafeHandle,或者应在使用者忘记调用Dispose的情况下替代Object.Finalize释放非托管资源。
重要
在 .NET Framework 中,C++ 编译器支持确定性资源处置,不允许直接实现 Dispose 该方法。
有关如何使用此接口和 Object.Finalize 方法的详细讨论,请参阅 垃圾回收 和 实现 Dispose 方法 主题。
使用实现 IDisposable 的对象
如果应用只是使用实现 IDisposable 接口的对象,则应在使用完该对象后调用该对象的 IDisposable.Dispose 实现。 根据编程语言,可以通过以下两种方式之一执行此操作:
- 通过使用语言构造,例如
using
C# 和 Visual Basic 中的语句,以及use
F# 中的语句或using
函数。 - 通过在块中
try
/finally
包装对实现的IDisposable.Dispose调用。
注意
有关实现 IDisposable 的类型的文档请注意这一事实,并包括调用其 Dispose 实现的提醒。
C#、F# 和 Visual Basic Using 语句
如果你的语言支持 C# 中的 using 语句、Visual Basic 中的 Using 语句或 F# 中的 use 语句等构造,则可以使用它,而不是显式调用IDisposable.Dispose自己。 以下示例在定义一个 WordCount
类时使用此方法来保留有关文件的信息及其单词数。
using System;
using System.IO;
using System.Text.RegularExpressions;
public class WordCount
{
private String filename = String.Empty;
private int nWords = 0;
private String pattern = @"\b\w+\b";
public WordCount(string filename)
{
if (!File.Exists(filename))
throw new FileNotFoundException("The file does not exist.");
this.filename = filename;
string txt = String.Empty;
using (StreamReader sr = new StreamReader(filename))
{
txt = sr.ReadToEnd();
}
nWords = Regex.Matches(txt, pattern).Count;
}
public string FullName
{ get { return filename; } }
public string Name
{ get { return Path.GetFileName(filename); } }
public int Count
{ get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions
type WordCount(filename) =
let txt =
if File.Exists filename |> not then
raise (FileNotFoundException "The file does not exist.")
use sr = new StreamReader(filename)
sr.ReadToEnd()
let pattern = @"\b\w+\b"
let nWords = Regex.Matches(txt, pattern).Count
member _.FullName = filename
member _.Name = Path.GetFileName filename
member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions
Public Class WordCount
Private filename As String
Private nWords As Integer
Private pattern As String = "\b\w+\b"
Public Sub New(filename As String)
If Not File.Exists(filename) Then
Throw New FileNotFoundException("The file does not exist.")
End If
Me.filename = filename
Dim txt As String = String.Empty
Using sr As New StreamReader(filename)
txt = sr.ReadToEnd()
End Using
nWords = Regex.Matches(txt, pattern).Count
End Sub
Public ReadOnly Property FullName As String
Get
Return filename
End Get
End Property
Public ReadOnly Property Name As String
Get
Return Path.GetFileName(filename)
End Get
End Property
Public ReadOnly Property Count As Integer
Get
Return nWords
End Get
End Property
End Class
using
语句(use
F# 中的表达式)实际上是语法便利。 在编译时,语言编译器为 try
/finally
块实现中间语言(IL)。
有关该语句的详细信息using
,请参阅 Using 语句或使用语句主题。
Try/Finally 块
如果编程语言不支持 C# 或 Visual Basic 中的语句或 F# 中的语句等using
构造,或者不想使用它,则可以从finally
语句块/try
finally
调用IDisposable.Dispose实现。use
以下示例将上一示例中的using
块替换为块/try
finally
。
using System;
using System.IO;
using System.Text.RegularExpressions;
public class WordCount2
{
private String filename = String.Empty;
private int nWords = 0;
private String pattern = @"\b\w+\b";
public WordCount2(string filename)
{
if (!File.Exists(filename))
throw new FileNotFoundException("The file does not exist.");
this.filename = filename;
string txt = String.Empty;
StreamReader? sr = null;
try
{
sr = new StreamReader(filename);
txt = sr.ReadToEnd();
}
finally
{
if (sr != null) sr.Dispose();
}
nWords = Regex.Matches(txt, pattern).Count;
}
public string FullName
{ get { return filename; } }
public string Name
{ get { return Path.GetFileName(filename); } }
public int Count
{ get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions
type WordCount2(filename) =
let txt =
if File.Exists filename |> not then
raise (FileNotFoundException "The file does not exist.")
let sr = new StreamReader(filename)
try
sr.ReadToEnd()
finally
sr.Dispose()
let pattern = @"\b\w+\b"
let nWords = Regex.Matches(txt, pattern).Count
member _.FullName = filename
member _.Name = Path.GetFileName filename
member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions
Public Class WordCount2
Private filename As String
Private nWords As Integer
Private pattern As String = "\b\w+\b"
Public Sub New(filename As String)
If Not File.Exists(filename) Then
Throw New FileNotFoundException("The file does not exist.")
End If
Me.filename = filename
Dim txt As String = String.Empty
Dim sr As StreamReader = Nothing
Try
sr = New StreamReader(filename)
txt = sr.ReadToEnd()
Finally
If sr IsNot Nothing Then sr.Dispose()
End Try
nWords = Regex.Matches(txt, pattern).Count
End Sub
Public ReadOnly Property FullName As String
Get
Return filename
End Get
End Property
Public ReadOnly Property Name As String
Get
Return Path.GetFileName(filename)
End Get
End Property
Public ReadOnly Property Count As Integer
Get
Return nWords
End Get
End Property
End Class
有关模式的详细信息 try
/finally
,请参阅 Try...抓住。。。最后语句, 最后尝试, 尝试...finally Expression,或 try-finally 语句。
实现 IDisposable
如果类型直接使用非托管资源,或者希望自己使用可释放资源,则应实现 IDisposable 。 当不再需要实例时,类型的 IDisposable.Dispose 使用者可以调用实现来释放资源。 若要处理它们无法调用 Dispose的情况,应使用派生自 SafeHandle 的类来包装非托管资源,或者应重写 Object.Finalize 引用类型的方法。 在任一情况下,都使用 Dispose 该方法执行使用非托管资源(例如释放、释放或重置非托管资源)后所需的任何清理。 有关实现 IDisposable.Dispose的详细信息,请参阅 Dispose(bool) 方法重载。
重要
如果要定义使用非托管资源的基类,并且该基类具有或可能具有应释放的子类,则应实现 IDisposable.Dispose 该方法并提供第二个重载 Dispose
,如下一部分所述。
IDisposable 和继承层次结构
具有应可释放的子类的基类必须如下所示实现 IDisposable 。 每当在非 sealed
NotInheritable
Visual Basic 中(在 Visual Basic 中)实现IDisposable的任何类型时,都应使用此模式。
- 它应提供一个公共的非虚拟 Dispose() 方法和受保护的虚拟
Dispose(Boolean disposing)
方法。 - 该方法 Dispose() 必须调用
Dispose(true)
并取消最终确定性能。 - 基类型不应包括任何终结器。
以下代码片段反映了基类的释放模式。 它假定你的类型不会重写 Object.Finalize 该方法。
using System;
using System.IO;
using System.Runtime.InteropServices;
class BaseClass1 : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a FileStream instance.
FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
fs.Dispose();
// Free any other managed objects here.
//
}
disposed = true;
}
}
open System
open System.IO
type BaseClass1() =
// Flag: Has Dispose already been called?
let mutable disposed = false
// Instantiate a FileStream instance.
let fs = new FileStream("test.txt", FileMode.OpenOrCreate)
interface IDisposable with
// Public implementation of Dispose pattern callable by consumers.
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this
// Implementation of Dispose pattern.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
if not disposed then
if disposing then
fs.Dispose()
// Free any other managed objects here.
disposed <- true
Imports System.IO
Imports System.Runtime.InteropServices
Class BaseClass1 : Implements IDisposable
' Flag: Has Dispose already been called?
Dim disposed As Boolean = False
' Instantiate a FileStream instance.
Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(disposing:=True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then Return
If disposing Then
fs.Dispose()
' Free any other managed objects here.
'
End If
disposed = True
End Sub
End Class
如果确实重写该方法 Object.Finalize ,则类应实现以下模式。
using System;
class BaseClass2 : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
disposed = true;
}
~BaseClass2()
{
Dispose(disposing: false);
}
}
open System
type BaseClass2() =
// Flag: Has Dispose already been called?
let mutable disposed = false
interface IDisposable with
// Public implementation of Dispose pattern callable by consumers.
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this
// Implementation of Dispose pattern.
abstract Dispose: bool -> unit
override _.Dispose(disposing) =
if not disposed then
if disposing then
// Free any other managed objects here.
()
// Free any unmanaged objects here.
disposed <- true
override this.Finalize() =
this.Dispose false
Class BaseClass : Implements IDisposable
' Flag: Has Dispose already been called?
Dim disposed As Boolean = False
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(disposing:=True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then Return
If disposing Then
' Free any other managed objects here.
'
End If
' Free any unmanaged objects here.
'
disposed = True
End Sub
Protected Overrides Sub Finalize()
Dispose(disposing:=False)
End Sub
End Class
子类应实现以下可释放模式:
- 它们必须重写
Dispose(Boolean)
并调用基类Dispose(Boolean)
实现。 - 如果需要,他们可以提供终结器。 终结器必须调用
Dispose(false)
。
请注意,派生类本身不实现 IDisposable 接口,也不包括无 Dispose 参数方法。 它们仅重写基类 Dispose(Boolean)
方法。
以下代码片段反映了派生类的释放模式。 它假定你的类型不会重写 Object.Finalize 该方法。
using System;
using System.IO;
using System.Runtime.InteropServices;
class MyDerivedClass : MyBaseClass
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a FileStream instance.
FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
fs.Dispose();
// Free any other managed objects here.
//
}
// Free any unmanaged objects here.
//
disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}
open Microsoft.Win32.SafeHandles
open System
type MyDerivedClass() =
inherit MyBaseClass()
// Flag: Has Dispose already been called?
let mutable disposed = false
// Instantiate a FileStream instance.
let fs = new FileStream("test.txt", FileMode.OpenOrCreate)
// Implementation of Dispose pattern.
override _.Dispose(disposing) =
if not disposed then
if disposing then
fs.Dispose()
// Free any other managed objects here.
// Free any unmanaged objects here.
disposed <- true
// Call base class implementation.
base.Dispose disposing
Imports System.IO
Imports System.Runtime.InteropServices
Class DerivedClass2 : Inherits BaseClass2
' Flag: Has Dispose already been called?
Dim disposed As Boolean = False
' Instantiate a FileStream instance.
Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)
' Protected implementation of Dispose pattern.
Protected Overrides Sub Dispose(disposing As Boolean)
If disposed Then Return
If disposing Then
fs.Dispose()
' Free any other managed objects here.
'
End If
' Free any unmanaged objects here.
'
disposed = True
' Call base class implementation.
MyBase.Dispose(disposing)
End Sub
End Class