C#使用IDisposable还是SafeHandle?

12

我已经阅读了很多关于C#中终结器和IDisposable的内容。当我终于从这个关于终结器和IDisposable混乱不堪的事情中有所清晰时,突然之间,出现了这个SafeHandle玩意儿。

我的信念再次被彻底颠覆了。我应该使用什么?


3
用于什么,确切地说? - Hans Passant
1
具体来说,用于什么目的我不太清楚。现在有两个看起来非常相似的结构,我不知道在什么情况下应该使用哪一个。 - ill mg
1
@HansPassant 当阅读MSDN关于如何实现IDisposable的文章时,微软提出了两种实现方式。一种是实现终结器,而推荐的方法是使用SafeHandle。这确实有点令人困惑和误导,所以我很理解OP的问题。URL: http://msdn.microsoft.com/en-us/en-en/library/fs2xkftw%28v=vs.110%29.aspx该网站让人感觉非常通用,因此我第一次尝试使用SafeHandle来正确处理我的Pen对象,但效果并不好。 - Tom
我认为,当您需要处理代表内核对象(Windows操作系统)的句柄时,最好坚持使用SafeHandle。如果您想要包装一些非托管代码,请实现IDisposable接口。 - John Z. Li
3个回答

19

SafeHandle只在处理Win32互操作调用时有用。在Win32中,大多数对象都由“句柄”表示,包括窗口、互斥体等等。因此,.NET SafeHandle使用可释放模式确保Win32句柄被正确关闭。

因此,如果您正在使用Win32互操作调用并返回Win32句柄,则应使用SafeHandle。对于自己的对象,您应使用IDisposable和终结器。


但是 IDisposable 的整个意义在于释放非托管资源,不是吗?“你自己的对象”听起来含糊不清,因为对象既可以表示托管对象,也可以表示非托管对象,而且由于开发人员可以开发托管和非托管代码,并从托管代码中调用非托管代码,所以你对“自己”的定义也很模糊。 - Andrew Savinykh
@zespri - 如果你决定实现IDisposable,那就意味着你正在维护这个类/对象(即它是你的)。如果它是来自第三方库的对象,那么你就不能实现IDisposable(即它不是你的)。我并不是在指什么应该被处理,也不会在非托管代码中实现IDisposable。 - CodeNaked
但是如果它是来自第三方(托管)库的对象,您也无法实现 SafeHandle 吗?仅仅因为您很可能根本没有直接访问句柄的可见性?抱歉,我并不是在挑衅,只是想理解您的意思。 - Andrew Savinykh
我不确定你所说的“你也不能实现SafeHandle”是什么意思。通常情况下,你不应该从SafeHandle派生,而只能在使用Interop调用时使用它。原问题询问是否应该从SafeHandle派生或实现IDisposable。前者几乎从来不是一个好主意。所以只剩下后者了。而且你只能在你维护的类/对象上实现IDisposable(即你的类/对象)。所以我猜你困惑的是我用“对象”而不是“类”这个词吧? - CodeNaked
1
它变得太复杂了,如果您愿意,我们可以就此放弃。我不太确定为什么从SafeHandle派生几乎从来不是一个好主意。事实上,我认为在许多情况下(特别是当您尝试包装未托管的句柄时),这是一个更优秀的选择,因为如果您继承自SafeHandle,那么可以确保Finalizer会正确地为您实现。虽然这只是与我的原始查询相干,但它只会使我更加困惑。 - Andrew Savinykh

7
您可以/应该使用SafeHandle来处理任何可以表示为IntPtr的非托管资源,例如Win32句柄、由非托管代码分配的内存等。当SafeHandle不适用时,但仍需要处理非托管资源时,请考虑创建自己的类,类似于继承自CriticalFinalizerObject的SafeHandle。
在所有其他情况下(即处理托管资源),请实现IDisposable。在大多数情况下,您不需要终结器,大多数托管资源在调用终结器时将不可用,因此在那里没有任何事情要做。

2
在大多数情况下,我的建议是假装没有所谓的终结器,但一定要确保销毁任何创建的IDisposable对象。即使终结器编写得非常优化,正确处理了一半的对象并让终结器处理另一半对象的代码也不如完全正确处理所有对象并且不使用终结器的代码好。虽然通常情况下从未运行的终结器对性能的影响通常不会太严重,但是编写正确的终结器很困难,如果它们的代码或消费它们的代码不完美,它们可能会导致Heisenbugs。此外,成功实现终结器通常需要创建一个或多个弱引用,其唯一目的是支持终结。

也许终止保护网值得代价,但代价可能相当高,并且安全保障可能不如人们所希望的可靠。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接