如果你觉得你的类需要实现 IDisposable
接口,还是需要注意一些坑的。不过前人准备了 Dispose 模式 供我们参考,最大程度避免这样的坑。
C#程序中的 Dispose 方法,一旦被调用了该方法的对象,虽然还没有垃圾回收,但实际上已经不能再使用了。所以使用上要仔细考虑细节。
需要明确一下 C# 程序(或者说 .NET)中的资源。简单的说来,C# 中的每一个类型都代表一种资源,而资源又分为两类:
- 托管资源:由 CLR 管理分配和释放的资源,即由 CLR 里 new 出来的对象;
- 非托管资源:不受 CLR 管理的对象,Windows 内核对象,如文件、数据库连接、套接字、COM 对象等;
毫无例外地,如果我们的类型使用到了非托管资源,或者需要显式释放的托管资源,那么,就需要让类型继承接口 IDisposable
。这相当于是告诉调用者,该类型是需要显式释放资源的,你需要调用我的 Dispose
方法。
不过,这一切并不这么简单,一个标准的继承了 IDisposable
接口的类型应该像下面这样去实现。这种实现我们称之为 Dispose
模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class DisposableObject : IDisposable
{
/// <summary>
/// 获取或设置一个值。该值指示资源已经被释放。
/// </summary>
private bool _disposed;
/// <summary>
/// 执行与释放或重置非托管资源相关的应用程序定义的任务。
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// 关闭此对象使用的所有资源。
/// </summary>
public void Close()
{
Dispose();
}
/// <summary>
/// 由终结器调用以释放资源。
/// </summary>
~DisposableObject()
{
Dispose(false);
}
/// <summary>
/// 执行与释放或重置非托管资源相关的应用程序定义的任务。
/// 派生类中重写此方法时,需要释放派生类中额外使用的资源。
/// </summary>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// 清理托管资源
// if (managedResource != null)
// {
// managedResource.Dispose();
// managedResource = null;
// }
}
// 清理非托管资源
// if (nativeResource != IntPtr.Zero)
// {
// Marshal.FreeHGlobal(nativeResource);
// nativeResource = IntPtr.Zero;
// }
// 标记已经被释放。
_disposed = true;
}
}
本文会经常更新,请阅读原文: https://blog.walterlv.com/post/recommended-dispose-implementation.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。