54 .net c# idisposable
对于C++(析构函数)中的等效机制,建议通常不应抛出任何异常.这主要是因为这样做可能会终止您的流程,这很少是一个好策略.
在.NET的等效场景中......
...您的流程不会立即终止.但是,由于.NET无法用第二个异常替换第一个异常,因此会丢失信息.因此,调用堆栈上某处的catch块将永远不会出现第一个异常.然而,人们通常对第一个例外更感兴趣,因为这通常会提供更好的线索,说明为什么事情开始出错.
由于.NET缺少一种机制来检测代码是否在异常处于挂起状态时被执行,因此似乎只有两种选择可以实现IDisposable:
那么,两个邪恶中哪一个较小?有没有更好的办法?
编辑:为了澄清,我不是在谈论积极抛出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
{
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ric*_*ard 36
该框架设计指南(2 次 ED)有这样的(§9.4.1):
避免在Dispose(bool)中抛出异常,除非在包含进程已被破坏的临界情况下(泄漏,不一致的共享状态等).
评论[编辑]:
Dispose(bool)
可以从终结器调用,从终结器中抛出是一个坏主意,并将阻止其他对象被最终确定.我的观点:从Dispose中逃避的异常应该只是那些,如在指南中那样,充分的灾难性,以至于当前的过程不可能有进一步的可靠功能.
Mar*_*ell 17
我认为吞咽是这种情况下两种邪恶中较小的一种,因为最好提出原始 Exception
警告:除非,或许未能干净地处置本身是非常关键的(也许如果一个TransactionScope
无法处置,因为这可能表示回滚失败).
有关这方面的更多想法,请参阅此处 - 包括包装/扩展方法的想法:
using(var foo = GetDodgyDisposableObject().Wrap()) {
foo.BaseObject.SomeMethod();
foo.BaseObject.SomeOtherMethod(); // etc
} // now exits properly even if Dispose() throws
Run Code Online (Sandbox Code Playgroud)
当然,你也可以做一些奇怪的事情,你用原始和第二(Dispose()
)异常重新抛出一个复合异常 - 但是想一想:你可能有多个using
块......它很快就会变得无法管理.实际上,最初的例外是有趣的.
Dispose
应该设计为实现其目的,处理对象.此任务是安全的,并且在大多数情况下不会抛出异常.如果你看到自己抛出异常Dispose
,你应该三思而后行,看看你是否在做太多的东西.除此之外,我认为Dispose
应该像所有其他方法一样对待:处理如果你可以用它做某事,如果你做不到就让它冒泡.
编辑:对于指定的示例,我会编写代码,以便我的代码不会导致异常,但清除TcpClient
up可能会导致异常,这在我看来应该有效传播(或者作为更通用的处理和重新抛出异常,就像任何方法一样):
public void Dispose() {
if (tcpClient != null)
tcpClient.Close();
}
Run Code Online (Sandbox Code Playgroud)
但是,就像任何方法一样,如果你知道tcpClient.Close()
可能会抛出一个应该被忽略的异常(无关紧要)或者应该被另一个异常对象表示,你可能想要捕获它.
归档时间: |
|
查看次数: |
5845 次 |
最近记录: |