Dispose接口的正确使用方法
我们知道在代码里自己写 Dispose 来释放一些资源。但是你真的用对了吗 ? 本篇介绍一些不容易注意到的 GC 相关知识 。
到底什么时候需要使用到 IDispose ?
当前类中出现 IO 操作。或者其他 跨语言调用,窗口和网络连接 之的非托管资源调用,这时才需要自己是实现一个IDispose 接口。其他的时候你并不需要去实现这样一个接口。我的做法是一般的类继承一个 IReset 接口,这个接口内只包含一个 Reset 函数 .
Dispose 接口是一个显示的调用,如果我们没有写这个接口,运行时他会在执行析构函数的时候清理资源。
了解析构函数(终结器)
在使用Dispose 接口的同时 你或许同时会用到一个终结器。打个比方 如果你忘记显示调用 Dispose 函数的时候,程序还是会帮你清除非托管资源。
先观察以下析构函数
1 | class Car |
上面的代码很简单,他等价于下面的代码
1 | protected override void Finalize() |
现在你应该已经观察到这一行代码被隐式调用了,这行代码的意义是将当前运行时 Finalize 队列中创建一个条目,等待回收器来处理该队列。
1 | base.Finalize(); |
正确的 “Dispose”
我们再观察下面的代码
1 | public class MyClass |
上面我们使用了 GC.SuppressFinalize(this);
函数,他会告诉GC的Finalize队列中移除当前,不必在执行 Finalize()
注意事项
- 在非托管资源操作中才去重写dispose接口,否则使用其他自定义接口去实现 Reset 操作
- 在非托管资源操作中才去重写析构函数,否则空析构函数也会造成不必要的性能损失
- 重写dispose接口的同时别忘了重写析构函数
文外话
在 C# 语言里对析构函数与终结器的描述似乎是同一个东西,这让我有一点困惑。我查询了一些论文他们是这样说的。如果你感兴趣也可以看一下
In the C# world the terms “destructor” and “finalizer” seem to be used pretty much interchangeably, which I suspect is because the C# specification describes the non-deterministic cleanup functionality using the word “destructor”, whereas the CLR documentation always uses the word “finalizer”, so within the realms of C# they mean the same thing.
However, in the C++/CLI specification there is a distinction made between the two. It allows both deterministic and non-deterministic cleanup, and uses the term “destructor” for the deterministic functionality and “finalizer” for the non-deterministic functionality:
在C#世界术语“析构函数”和“终结”似乎要使用pretty多互换,我怀疑是因为C#规范用字“析构函数”,描述了非确定性的清理功能,而CLR的文档始终使用单词“终结”,所以C#的领域内,他们的意思是一样的。
然而,在C / CLI规范有两者之间作出区分。它同时允许确定性和非确定性的清理,并使用该确定的功能的非确定性的功能的术语“析构”和“终结”:
析构函数和终结器的区别?(The difference between a destructor and a finalizer?
本文标题:Dispose接口的正确使用方法
文章作者:Keyle
发布时间:2019-02-20
最后更新:2019-02-21
原始链接:https://vrast.cn/posts/6de8b164/
版权声明:©Keyle's Blog. 本站采用署名-非商业性使用-相同方式共享 4.0 国际进行许可