如何正确实现IDisposable接口
如果一个对象拥有非托管资源,则应该实现IDisposable接口,这样调用方可以在使用之后及时释放资源。
有很多关于.Net的书籍和文章都描述了如何实现IDisposable接口,但是几乎每一篇实现的都不完全一样,这里将几个主要的实现进行合并,试图找出能够适应绝大多数条件的实现方法。
实现代码
分析
Dispose()方法用于显式的释放资源,可以在代码中直接调用,或者使用using语句间接调用。GC.SuppressFinalize告诉GC在垃圾回收时,不需要调用析构函数,可以提高垃圾回收的效率。
Close()方法与Dispose()作用相同,只是为了适应某些有Open方法的类,Open/Close相互对应比较符合一般习惯。
析构函数用于在垃圾回收的时候释放资源。如果用户没有/忘记在使用之后释放资源,CLR会在垃圾回收的时候调用此函数。虽然资源较晚被释放,但总是好于不释放。
Dispose(bool)是真正释放资源的地方,参数disposing表明是用户主动释放资源还是在垃圾回收时释放。当用户主动释放资源时,由于此对象的成员中,某些托管资源持有非托管资源,因此需要释放这些托管资源,如果这些托管资源实现了IDisposable,调用Dispose()即可。在垃圾回收时,由于无法确定这些托管资源是否已经被回收了,因此不要试图释放托管资源,GC会释放这些资源的。如果多次调用Dispose(bool)会有副作用,则需要添加disposed变量来判断是否已经释放了资源。如果对象可能会在多线程环境中使用,需要加锁防止同步问题。
最后,如果该类有派生类的话,要在派生类中override父类的Dispose(bool)方法,并在释放资源后调用父类的Dispose(bool),以正确释放父类的资源。
有很多关于.Net的书籍和文章都描述了如何实现IDisposable接口,但是几乎每一篇实现的都不完全一样,这里将几个主要的实现进行合并,试图找出能够适应绝大多数条件的实现方法。
实现代码
1
namespace Disposable
2
{
3
public class ResourceBase:IDisposable
4
{
5
private bool disposed = false;
6
7
~ResourceBase()
8
{
9
Dispose(false);
10
}
11
12
protected virtual void Dispose(bool disposing)
13
{
14
if (disposed)
15
return;
16
//多线程环境
17
lock (this)
18
{
19
if (disposing)
20
{
21
//release managed resource
22
}
23
//release unmanaged resource;
24
disposed = true;
25
}
26
}
27
public void Close()
28
{
29
Dispose();
30
}
31
32
IDisposable Members
41
}
42
public class Resource:ResourceBase
43
{
44
private bool disposed = false;
45
protected override void Dispose(bool disposing)
46
{
47
if (disposed)
48
return;
49
//多线程环境
50
lock (this)
51
{
52
try
53
{
54
if (disposing)
55
{
56
//release managed resource
57
}
58
//release unmanaged resource
59
60
}
61
finally
62
{
63
base.Dispose(disposing);
64
disposed = true;
65
}
66
67
}
68
69
}
70
}
71
}
namespace Disposable2
{3
public class ResourceBase:IDisposable4
{5
private bool disposed = false;6

7
~ResourceBase()8
{9
Dispose(false);10
}11

12
protected virtual void Dispose(bool disposing)13
{14
if (disposed)15
return;16
//多线程环境17
lock (this)18
{19
if (disposing)20
{21
//release managed resource22
}23
//release unmanaged resource;24
disposed = true;25
}26
}27
public void Close()28
{29
Dispose();30
}31

32
IDisposable Members41
}42
public class Resource:ResourceBase43
{44
private bool disposed = false;45
protected override void Dispose(bool disposing)46
{47
if (disposed)48
return;49
//多线程环境50
lock (this)51
{52
try53
{54
if (disposing)55
{56
//release managed resource57
}58
//release unmanaged resource59
60
}61
finally62
{63
base.Dispose(disposing);64
disposed = true;65
}66

67
}68
69
}70
}71
}分析
Dispose()方法用于显式的释放资源,可以在代码中直接调用,或者使用using语句间接调用。GC.SuppressFinalize告诉GC在垃圾回收时,不需要调用析构函数,可以提高垃圾回收的效率。
Close()方法与Dispose()作用相同,只是为了适应某些有Open方法的类,Open/Close相互对应比较符合一般习惯。
析构函数用于在垃圾回收的时候释放资源。如果用户没有/忘记在使用之后释放资源,CLR会在垃圾回收的时候调用此函数。虽然资源较晚被释放,但总是好于不释放。
Dispose(bool)是真正释放资源的地方,参数disposing表明是用户主动释放资源还是在垃圾回收时释放。当用户主动释放资源时,由于此对象的成员中,某些托管资源持有非托管资源,因此需要释放这些托管资源,如果这些托管资源实现了IDisposable,调用Dispose()即可。在垃圾回收时,由于无法确定这些托管资源是否已经被回收了,因此不要试图释放托管资源,GC会释放这些资源的。如果多次调用Dispose(bool)会有副作用,则需要添加disposed变量来判断是否已经释放了资源。如果对象可能会在多线程环境中使用,需要加锁防止同步问题。
最后,如果该类有派生类的话,要在派生类中override父类的Dispose(bool)方法,并在释放资源后调用父类的Dispose(bool),以正确释放父类的资源。


浙公网安备 33010602011771号