对于 C++ 中的等效机制(析构函数),建议是 it should usually not throw any exceptions .这主要是因为这样做可能会终止您的进程,这很少是一个好策略。
在 .NET 中的等效场景中......
- 抛出第一个异常
- finally block 作为第一个异常的结果执行
- finally block 调用 Dispose() 方法
- Dispose() 方法抛出第二个异常
...您的进程不会立即终止。但是,您会丢失信息,因为 .NET 粗暴地将第一个异常替换为第二个异常。因此,调用堆栈上方某处的 catch block 永远不会看到第一个异常。但是,人们通常对第一个异常更感兴趣,因为它通常会提供更好的线索,说明为什么事情开始出错。
由于 .NET 缺乏一种机制来检测代码是否在异常挂起时正在执行,因此似乎只有两种选择如何实现 IDisposable:
- 始终吞并 Dispose() 中发生的所有异常。不好,因为您最终可能还会吞下 OutOfMemoryException、ExecutionEngineException 等,我通常宁愿在它们发生时拆除进程,而没有另一个异常已经挂起。
- 让所有异常传播到 Dispose() 之外。不好,因为您可能会丢失有关问题根本原因的信息,请参见上文。
那么,两害相权取其轻?有没有更好的办法?
编辑:澄清一下,我不是在谈论是否主动从 Dispose() 抛出异常,我是在谈论让 Dispose() 调用的方法抛出的异常传播到 Dispose 之外() 与否,例如:
using System;
using System.Net.Sockets;
public sealed class NntpClient : IDisposable
{
private TcpClient tcpClient;
public NntpClient(string hostname, int port)
{
this.tcpClient = new TcpClient(hostname, port);
}
public void Dispose()
{
// Should we implement like this or leave away the try-catch?
try
{
this.tcpClient.Close(); // Let's assume that this might throw
}
catch
{
}
}
}
最佳答案
Framework Design Guidelines(第 2nd 版)将其作为 (§9.4.1):
AVOID throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted (leaks, inconsistent shared state, etc.).
评论[编辑]:
- 有指导方针,而不是硬性规定。这是一个“避免”而不是“不要”的指南。正如(在评论中)指出的那样,该框架在某些地方打破了这个(和其他)指南。诀窍是知道何时打破准则。在很多方面,这就是熟练工和大师之间的区别。
- 如果清理的某些部分可能失败,则应提供一个 Close 方法,该方法将抛出异常,以便调用者可以处理它们。
- 如果您遵循处置模式(如果类型直接包含一些非托管资源,您应该这样做)那么可以从终结器调用
Dispose(bool)
,从终结器抛出是一个坏主意,会阻止其他对象被最终确定。
我的观点:从 Dispose 中逃逸的异常应该只是那些,如指南中所述,具有足够的灾难性,以至于无法从当前进程中获得进一步的可靠功能。
关于c# - 您是否应该实现 IDisposable.Dispose() 以使其永远不会抛出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/577607/