确定是否由于抛出异常而在finally块中执行

Dan*_*ant 33 c# idisposable exception finally try-catch

是否可以通过finally抛出异常来确定代码当前是否在处理程序的上下文中执行?我非常喜欢使用IDisposable模式来实现入口/出口作用域功能,但是这种模式的一个问题是,如果在主体中发生异常,您可能不一定希望发生作用域结束行为using.我会找这样的东西:

public static class MyClass
{
    public static void MyMethod()
    {
        using (var scope = MyScopedBehavior.Begin())
        {
            //Do stuff with scope here
        }
    }
}

public sealed class MyScopedBehavior : IDisposable
{
    private MyScopedBehavior()
    {
        //Start of scope behavior
    }

    public void Dispose()
    {
        //I only want to execute the following if we're not unwinding
        //through finally due to an exception:
        //...End of scope behavior    
    }

    public static MyScopedBehavior Begin()
    {
        return new MyScopedBehavior();
    }
}
Run Code Online (Sandbox Code Playgroud)

还有其他方法可以实现这一点(将委托传递给围绕具有特定行为的调用的函数),但我很好奇是否可以使用该IDisposable模式来完成它.


实际上,这显然已经在之前得到了回答.有可能以一种非常黑客的方式进行检测.我实际上不会使用这种技术,但知道这是可能的,这很有趣.

Ree*_*sey 17

我见过的实现这个目标的方法需要一个额外的方法:

public static void MyMethod()
{
    using (var scope = MyScopedBehavior.Begin())
    {
        //Do stuff with scope here
        scope.Complete(); // Tells the scope that it's good
    }
}
Run Code Online (Sandbox Code Playgroud)

通过执行此操作,您的范围对象可以跟踪由于错误或成功操作而处置它.这是TransactionScope采用的方法,例如(参见TransactionScope.Complete).


the*_*oop 14

作为一个侧面点,IL允许您指定SEH fault块,这些块类似finally在抛出异常时才输入- 您可以在此处看到一个示例,大约是页面下方的2/3rds.不幸的是,C#没有公开这个功能.

  • 从来没听说过.VB.NET暴露了`filter`(也在帖子中提到),但C#没有.这样的时候我希望我可以扩展C#编译器来添加这些额外的语法:/ (2认同)

dmo*_*dmo 7

我正在为单元测试寻找类似的东西 - 我有一个帮助类,我用它来测试运行后清理对象,我想保持漂亮,干净的'使用'语法.如果测试失败,我还想要不清理的选项.我想出的是调用Marshal.GetExceptionCode().我不知道这是否适用于所有情况,但对于测试代码,它似乎工作正常.


Bri*_*sio 5

我能想到的最好的是:

using (var scope = MyScopedBehavior.Begin())
{
  try
  {
    //Do stuff with scope here
  }
  catch(Exception)
  {
    scope.Cancel();
    throw;
  }
}
Run Code Online (Sandbox Code Playgroud)

当然,scope.Cancel()确保在Dispose()中没有任何反应