Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在我在.NET中输入finally块之前是否可能检测到异常?_C#_.net_Exception - Fatal编程技术网

C# 在我在.NET中输入finally块之前是否可能检测到异常?

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

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.
        }
    }
}
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
的一部分。它是简化的示例代码。我不能重构它,因为它所派生的真实代码不允许重构,因为您的假设不再有效。