Java也提出了同样的问题,但我对.NET的答案很感兴趣.
请考虑以下代码:
class Program
{
static void Main()
{
try
{
RunTransaction();
// If there was an exception within the transaction,
// I won't be here anymore. But if the transaction was
// cancelled without an exception being thrown, I really
// need to know because I must stop here anyway.
OtherCode();
}
catch (Excexption ex)
{
// Log the exception...
// If an exception was thrown in the transaction scope,
// this must be logged here. If a "helper" exception was
// created in the Dispose method, this may be logged, but
// it won't say much. It just made sure that nothing else
// was executed in this try block.
}
}
static void RunTransaction()
{
using (var trans = new Transaction())
{
// An error may occur here and it should be logged.
throw new Exception();
// Maybe the scope is simply left without an exception.
return;
// Otherwise, the transaction is committed.
trans.Commit();
}
}
}
class Transaction : IDisposable
{
bool isCommitted;
public void Commit()
{
isCommitted = true;
}
public void Dispose()
{
if (!isCommitted)
{
// Was an exception thrown before this is called?
// If not, I might consider throwing one here.
// I can't always throw an exception here because if
// another exception is already propagated, it would
// be dropped and the real error cause would not be
// visible anymore.
}
}
}
Run Code Online (Sandbox Code Playgroud)
在该Transaction.Dispose方法中,我如何知道是否已抛出异常?
请注意,finally此处未显式显示该块,但隐藏在using调用该IDisposable.Dispose方法的语句中,此处显示该方法.
更新:我的背景是我有一个行为包装类,行为有点像TransactionScope.但是TransactionScope太多魔术并没有按预期工作,所以我回到真正的数据库交易.有些方法需要一个事务,但是如果它们是从另一个已经需要事务的方法调用的,那么内部"事务"必须"连接"外部事务而不是从数据库请求一个新的嵌套事务,这在任何地方都不受支持.了解.真实代码比我的样本复杂一点,内部事务可能被取消,有效地结束了事务.然后,如果在外部事务中继续运行任何东西,它不再存在,则无法回滚,但会在任何事务之外有效地运行!必须一定要防止这种情况.首先处理异常就可以了,但是内部事务也可以在没有它的情况下取消.这是我想在我的作用域助手类中检测到的.
public void Dispose()
{
if (!isCommitted)
{
// Was an exception thrown before this is called?
// If not, I might consider throwing one here.
// I can't always throw an exception here because if
// another exception is already propagated, it would
// be dropped and the real error cause would not be
// visible anymore.
}
}
Run Code Online (Sandbox Code Playgroud)
你说你想抛出异常,Dispose如果没有抛出异常.
但Dispose不应该抛出异常.从实现Dispose方法:
为了确保始终适当地清理资源,Dispose方法应该可以多次调用,而不会抛出异常.
同样来自Dispose Pattern:
避免从内部抛出异常,
Dispose(bool)除非在包含进程已被破坏的临界情况下(泄漏,不一致的共享状态等).用户希望调用
Dispose不会引发异常.如果
Dispose可能引发异常,则最终块清理逻辑将不会执行.要解决这个问题,用户需要Dispose在try块中包含每个调用(在finally块中!),这会导致非常复杂的清理处理程序.如果执行Dispose(bool disposing)方法,则在disposing为false时永远不会抛出异常.如果在终结器上下文中执行,这样做将终止进程.