C# 在我在.NET中输入finally块之前是否可能检测到异常?
Java也有同样的问题,但我对.NET的答案感兴趣 考虑以下代码:C# 在我在.NET中输入finally块之前是否可能检测到异常?,c#,.net,exception,C#,.net,Exception,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 tra
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.
}
}
}
在Transaction.Dispose
方法中,如何知道是否已引发异常
请注意,finally
块在这里没有显式显示,而是隐藏在using
语句中,该语句调用IDisposable.Dispose
方法,如图所示
更新:我的背景是我有一个事务包装器类,其行为有点像TransactionScope
。但是TransactionScope
太神奇了,不能像预期的那样工作,所以我回到了真实的数据库事务。有些方法需要事务,但如果从另一个已经需要事务的方法调用它们,则内部“事务”必须“连接”外部事务,而不是从数据库请求新的嵌套事务,这在我所知的任何地方都不受支持。真正的代码比我的示例要复杂一些,在我的示例中,可以取消内部事务,从而有效地结束事务。然后,如果任何东西继续在外部事务中运行(该事务已不存在),它将无法回滚,但将有效地在任何事务之外运行!这必须通过一切手段加以防止。首先授权一个异常就可以了,但是内部事务也可以在没有授权的情况下被取消。这就是我想要在scope helper类中检测的内容
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.
}
}
如果尚未引发异常,则表示希望从Dispose
引发异常
但是Dispose
不应该抛出异常。发件人:
为了帮助确保资源始终得到适当的清理,Dispose方法应该可以多次调用,而不会引发异常
也来自:
避免从Dispose(bool)
中引发异常,除非在包含进程已损坏的关键情况下(泄漏、共享状态不一致等)
用户希望调用Dispose
不会引发异常
如果Dispose
可能引发异常,则最终不会执行块清理逻辑。为了解决这个问题,用户需要将对Dispose
(在finally块中!)的每个调用包装在try块中,这会导致非常复杂的清理处理程序。如果执行Dispose(bool disposing)
方法,如果disposing为false,则永远不要抛出异常。如果在终结器上下文中执行,则这样做将终止进程
您需要问自己的问题是“为什么这个对象有任何业务需要知道是否存在异常?”。也许我在这里错了,但这似乎是因为您认为
RunTransaction()
与事务本身有关,这是一个错误的假设,因为代码似乎位于transaction
类之外
重构代码的方法是:
class Transaction : IDisposable
{
bool isCommitted;
public void Commit() { ... }
public void Dispose() { ... }
public void RunTransaction() { ... }
}
这样,如果RunTransaction()
抛出,您就可以知道
编辑:或者,如果代码必须位于事务类之外,则可以进一步重构事务
以执行以下操作:
public void RunTransaction(Action action) { ... }
并以以下方式调用它:
trans.RunTransaction(() => RunTransaction());
可能重复按ctrl+alt+e并标记clr Exception复选框如果您想知道事务是否已取消,为什么不从方法返回一个指示是否已取消的值?您到底想实现什么?某种类型的保护,以确保没有提交的代码不会从事务块返回?我很难理解您试图如何处理它。如果发生异常,您可以在外部记录异常。您不应该在
Dispose()中抛出。我可能遗漏了一些东西,但这能为您带来什么?OP想知道异常是否在Dispose()
@johnymapp Yes之前触发,他想知道这一点,因为他想从Dispose
抛出一个异常,如果还没有抛出的话。但是由于Dispose
不应该抛出异常,这一点是没有意义的。虽然文档是正确和合理的,但我的Dispose方法不是释放资源,而是使用IDisposable
模式实现。我也可以编写try/finally
,没有IDisposable
界面,也可以同样工作。在这里,它只是一个保持代码更干净的助手。C#sugar.@LonelyPixel那么我会说你误用了这个功能。也许吧。你能想象我用try/finally来代替吗?问题仍然是一样的。我同意你的第一段,但我认为你的代码样本被误导了RunTransaction()
可能只是执行事务代码的所有函数的占位符-它可能不是运行某个事务的通用包装器,因此它不应该是transaction
的一部分。它是简化的示例代码。我不能重构它,因为它所派生的真实代码不允许重构,因为您的假设不再有效。