如何从嵌套的try-catch块内部重新抛出先前的异常?(c#)

本文关键字:异常 新抛出 嵌套 try-catch 内部 | 更新日期: 2023-09-27 18:12:26

我有一个尝试类型转换的代码。如果它失败了,我想尝试其他方法,如果也失败了,那么重新抛出第一次转换尝试的原始异常。问题是,我所知道的唯一重新抛出的方法是让"throw;"坐在catch块的末尾。当我只希望从另一个catch块内发生重新抛出时会发生什么?

try 
{
    valueFromData = Convert.ChangeType(valueFromData, pi.PropertyType);
} 
catch(InvalidCastException e)
{
    Debug.WriteLine(String.Concat("Info - Direct conversion failed. Attempting to convert using String as an intermidiate type."));
    try { valueFromData = Convert.ChangeType(valueFromData.ToString(), pi.PropertyType); }
    catch { throw e; }
}

正如你在上面看到的,我必须使用' throw e; ',它重置了调用堆栈。

到目前为止,我想到的唯一一个解决方法(在我看来)很恶心:

bool handled = true;
... 
catch { handled = false; }
if( !handled ) throw;

如何从嵌套的try-catch块内部重新抛出先前的异常?(c#)

没有办法从inner捕获块内部的外部catch块重新抛出异常。实现此模式的最佳方法是注意内部操作是否成功

catch (InvalidCastException e) {
  bool threw = false;
  try {
    ...
  } catch { 
    threw = true;
  }
  if (threw) {
    throw;
  }
}

如果您打算进行多次转换尝试,那么在适用的情况下使用非抛出操作当然是有意义的,这样您就可以完全避开这个问题。

假设为了论证,这是不可能的,下一步是质疑throw e;方法。在您给出的示例代码中,恕我直言,如果您的throw重置调用堆栈,则根本没有问题。一旦有人找到了这个方法的源代码(修改后的调用堆栈仍然指向它),我认为发生的事情就很明显了。因此,虽然重置调用堆栈总是一个有问题的决定,但在这个特殊的情况下,应该允许发生,因为没有明显的缺点。

最后,你提到的解决方法既有趣又恶心(我同意这一点!)。

我尝试了以下方法,似乎实现了您的目标,当第二个异常发生时(在这种情况下,ArgumentException)它会抛出第一个异常(InvalidCastException)

[TestMethod]
[ExpectedException(typeof(InvalidCastException))]
public void ReThrowException() {
    var ret = false;
    try {
        ret = F1(1);
    }
    catch (InvalidCastException ex) {
        try {
            ret = F1(2);
        }
        catch (Exception e) {
            Debug.WriteLine(e.Message);
            throw ex;
        }
    }
}

private bool F1(int i) {
    if (i == 1) {
       throw new InvalidCastException();
    } else {
       throw new ArgumentException();
    }
    return false;
}

希望有帮助,

Alan。