如何在运行时检测程序是否在抛出异常的情况下执行?

6

在Helper()方法中,我能否在运行时检测程序执行是否是由于抛出异常而导致的?

注意,我的目标是避免扩展Helper()方法以接受异常对象作为输入参数。

public void MyFunc1()
{
  try
  {
    // some code here that eventaully throws an exception
  }
  catch( Exception ex )
  {
     Helper();
  }
}

public void MyFunc2()
{
   Helper();
}

private void Helper()
{
    // how can I check if program execution is the  
    // result of a thrown exception here.
}
4个回答

10

有一种可怕的黑客技巧,涉及到Marshal.GetExceptionPointersMarshal.GetExceptionCode,但并不适用于所有平台,具体如下:

public static Boolean IsInException()
{
   return Marshal.GetExceptionPointers() != IntPtr.Zero ||
          Marshal.GetExceptionCode() != 0;
}

从这个页面: http://www.codewrecks.com/blog/index.php/2008/07/25/detecting-if-finally-block-is-executing-for-an-manhandled-exception/

本文讨论了如何检测try-catch语句块中的finally块是否执行,特别是在处理未处理异常时。本文提供了一个名为"DetectFinallyBlockExecution"的C#函数来演示如何实现此功能。如果finally块被执行,则该函数将返回true,否则将返回false。

2
+1/2 分是因为疯狂的解决方案,另外+1/2 分是因为说它是可怕的黑客行为。 - Simon_Weaver
这仅适用于最初作为Windows SEH异常的异常。例如NullReference或AccessViolation。 - Hans Passant
感谢你的精准,汉斯。还有感谢你的半分,西蒙。我认为还有另一种“更干净”的黑客方式,涉及到堆栈帧的检查,但是我需要睡觉了,下次再试试 :-)。 - jdehaan
谢谢,这是我所问问题中最正确的答案。 - Zamboni
哇,不是这样的。从GetExceptionCode()中获取某些内容是异常情况。 - Hans Passant
1
@HansPassant:使用普通的 throw new Exception() 对我来说很好用。也许这已经改变了? - porges

4
我想不出任何理由,为什么你不会像这样做:

private void Helper(bool exceptionWasCaught)
{
    //...
}

在一个完美的世界里,我同意;然而,我的例子简化了我的情况,我试图避免改变 Helper 方法的签名。 - Zamboni
StackFrame类:不行。无法找出异常是否被处理。全局变量。 - Hans Passant
谢谢,我同意你的答案。当时我在代码中深入了几层,不想改变方法签名,所以我才问这个问题的。最后,根据得到的答案,我决定改变签名。 - Zamboni

2
我不知道有没有这样的功能。虽然这种方法有些麻烦,但它完全阐明了开发者的意图。
private bool inException = false;

public void MyFunc1()
{
  try
  {
    inException = false;

    // some code here that eventaully throws an exception
  }
  catch( Exception ex )
  {
     inException = true;
     Helper();
  }
}

public void MyFunc2()
{
   inException = false;
   Helper();
}

private void Helper()
{
    // how can I check if program execution is the  
    // result of a thrown exception here.
    if (inException)
    {
        // do things.
    }
}

抱歉,但这是非常糟糕的设计,我永远不会建议使用那样的代码!请大家不要使用这段代码!采用“Hans Passant”版本或更好的方法,而不是传递布尔值。 - Scordo
在理想的情况下我同意;然而,我的例子简化了我的情况,我试图避免改变 Helper 方法的签名。- Zamboni 2 分钟前 - Puppy
1
@Scordo:我特意说了它并不是那么好。很多时候,人们继承的代码中方法的签名不能轻易地改变。我同意Hans的方式,毫无疑问。如果你能展示一种对方法签名影响最小且更加简洁的解决方案,请贡献出来。 - Jesse C. Slicer
@Zamboni:我没有改变方法签名。实际上,正如你在对汉斯的评论中指出的那样,我明确地没有这样做。 - Jesse C. Slicer
3
+1只是因为这是唯一不修改Helper签名且回答原问题的方法。是的,这很糟糕,但只是因为原问题已经很糟糕(用于捕获异常)。 - Daniel Earwicker

1
我觉得你有点想多了。如果你有异常,就传递异常。如果没有,就不用传递。
为什么你不想改变Helper()方法的签名?
public void MyFunc1()
{
  try
  {
    // some code here that eventually throws an exception
  }
  catch( Exception ex )
  {
     Helper(ex);
  }
}

private void Helper(Exception ex = null)
{
    // result of a thrown exception here.
    if (ex!=null)
    {
        // do things.
    } else {
        // do other things
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接