Sylvain B.
Sylvain B.

Reputation: 739

c# re-throw exception in a method designed to handle exceptions and preserve stacktrace

I want to write a method that handle exceptions and that will be called inside a catch block. Depending on the type of the exception passed, the exception is either passed as an inner exception of a new exception or simply re-thrown. How to preserve stack trace in the second case ?

Example :

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);
}

What I would not like to do is, because the pattern is repeated in many places and there will be no factorization :

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

Upvotes: 3

Views: 783

Answers (3)

Sefe
Sefe

Reputation: 14007

You need to use throw without specifying the exception to preserve stack trace. This can only be done inside the catch block. What you can do is return from HandleException without throwing the original exception and then use throw right afterwards:

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);
}

As long as you only use is to categorize the exception, the preferred way is two catch blocks:

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);
    }
}

With C# 6.0 you can also use when to let the exception fall through:

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);
    }
}

Upvotes: 6

spender
spender

Reputation: 120450

Actually, there's a really nice way of doing this in .Net4.5 using 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(); 
    }
}

Upvotes: 3

atomkiwi
atomkiwi

Reputation: 1

Maybe you can try this.

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

Upvotes: -2

Related Questions