C# 在旨在处理异常和保留堆栈跟踪的方法中重新引发异常



我想编写一个处理异常的方法,该方法将在catch块中调用。根据传递的异常的类型,异常要么作为新异常的内部异常传递,要么只是重新引发。在第二种情况下如何保留堆栈跟踪?

例:

public void TestMethod()
{
    try
    {
        // can throw an exception specific to the project or a .Net exception 
        SomeWorkMethod() 
    }
    catch(Exception ex)
    {
        HandleException(ex);
    }
}
private void HandleException(Exception ex)
{
    if(ex is SpecificException)
         throw ex; //will not preserve stack trace...
    else
         throw new SpecificException(ex);
}

我不想做的是,因为该模式在很多地方重复并且不会有因式分解:

try
{
    SomeWorkMethod();
}
catch(Exception ex)
{
    if(ex is SpecificException)
         throw;
    else
         throw new SpecificException(ex);
}
您需要

在不指定异常的情况下使用throw以保留堆栈跟踪。这只能在catch块内完成。您可以做的是从HandleException返回而不抛出原始异常,然后立即使用 throw

public void TestMethod()
{
    try
    {
        // can throw an exception specific to the project or a .Net exception 
        SomeWorkMethod() 
    }
    catch(Exception ex)
    {
        HandleException(ex);
        throw;
    }
}
private void HandleException(Exception ex)
{
    if(ex is SpecificException)
         return;
    else
         throw new SpecificException(ex);
}

只要只使用 is 对异常进行分类,首选方法是两个 catch 块:

public void TestMethod()
{
    try
    {
        // can throw an exception specific to the project or a .Net exception 
        SomeWorkMethod() 
    }
    catch (SpecificException)
    {
        throw;
    }
    catch(Exception ex)
    {
        throw new SpecificException(ex);
    }
}

在 C# 6.0 中,还可以使用 when 让异常消失:

public void TestMethod()
{
    try
    {
        // can throw an exception specific to the project or a .Net exception 
        SomeWorkMethod() 
    }
    catch(Exception ex) when (!(ex is SpecificException))
    {
        throw new SpecificException(ex);
    }
}

实际上,在 中有一个非常好的方法可以做到这一点。Net4.5 使用 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture

void Main()
{
    try
    {
        throw new Exception(); //appears to be thrown from here
    }
    catch(Exception ex)
    {
        ThrowEx(ex);
    }
}
public void ThrowEx(Exception ex)
{
    if(someCondition)
    {
        //we're in the scope of a `catch` and the exception
        //is "active", so the exception with original stack-trace
        //can be re-thrown with
        ExceptionDispatchInfo.Capture(ex).Throw();
        //the following line is unreachable, but the compiler doesn't realise
        //so we can "tell" the compiler that this branch ends in an exception
        //and avoid having to return anything in the non-void case
        throw new Exception(); 
    }
}

也许你可以试试这个。

if(ex.Gettype() == typeof(SpecificException))

最新更新