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);
}
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);
}
}
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With