Proper way to rethrow an exception - c#

I have the following methods in c#:
void Method1()
{
try
{
Method2();
}
catch(Method2Exception ex)
{
//Log error
}
}
void Method2()
{
if(error)
{
throw(new Method2Exception("error"));
}
//Do something and call method3
try
{
Method3();
}
catch(Method3Exception)
{
//??
}
}
void Method3()
{
//Do something
if(error)
{
throw(new Method3Exception("error"));
}
}
Method3 its gonna be call by different methods and it returns Method3Exception and I need rethrow the exception from Method2 to Method1 but I don't want catch Method3Exception on Method1. what's the best way to do that?
Any suggestions

The term (re)throw usally refer to throwing the exception back to the caller preserving the stack trace (which contains where the exception exactly occurred). This can be done using throw; without specifying the exception operand contrary to throw ex:
try
{
Method3();
}
catch(Method3Exception)
{
throw;
}
However, if you're just going to add a throw with nothing before it in that method. It is useless, just remove the try..catch and the exception is going to propagate to the caller which is the default behavior.
Docs:
A throw statement can be used in a catch block to re-throw the
exception that the catch block caught. In this case, the throw
statement does not take an exception operand.

Alternative way to re-throwing the exception (using throw; as described in other answers) is to wrap the exception in inner exception. As described in MSDN, all custom exceptions should have at least four constructors, and one of them is
public InvalidDepartmentException(string message, System.Exception inner) : base(message, inner) { }
So if all your custom exceptions are like this, you could wrap the exception from Method3 as inner exception:
void Method2()
{
if(error)
{
throw(new Method2Exception("error"));
}
//Do something and call method3
try
{
Method3();
}
catch(Method3Exception exc)
{
throw new Method2Exception("error", exc); // exc is passed as inner exception
}
}
Then if you want to inspect the inner exception in Method1, you can use property InnerException:
void Method1()
{
try
{
Method2();
}
catch(Method2Exception ex)
{
if(ex.InnerException != null)
{
var message = ex.InnerException.Message;
// Do what you need with the message
}
}
}

In Method2, you can throw a new Method2Exception with the existing Method3Exception as its InnerException:
try
{
Method3();
}
catch(Method3Exception method3Exception)
{
throw new Method2Exception("Message", method3Exception);
}
Then you can catch the Method2Exception above:
try
{
Method2();
}
catch(Method2Exception ex)
{
//Log error
}

Exceptions are bubbles up by default. For example,
void FirstMethod()
{
int a = 0;
int b = 10;
int c = b / a;
}
void SecondMethod()
{
FirstMethod();
}
void ThirdMethod()
{
SecondMethod();
}
void FourthMethod()
{
try
{
ThirdMethod();
}
catch (DivideByZeroException ex)
{
// Handle error
}
}
The exception will occur in FirstMethod and it will go upwards and will be cought at ForurthMethod. If you want to log the exception at ThirdMethod for example, but still want your exception to be handled at FourthMethod then you have to options:
First option:
void ThirdMethod()
{
try
{
SecondMethod();
}
catch (Exception ex)
{
// Log the error
throw; // Throw exception without affecting StackTrace
}
}
Second option:
After C# 6.0 you can do this with ease by using exception filters. Create a logger method which returns false.
bool Log(Exception ex)
{
// Log the error
return false;
}
Add exception filter in third method:
void ThirdMethod()
{
try
{
SecondMethod();
}
catch (Exception ex) when(Log(ex))
{
// Debugger won't reach here
}
}

Related

Try on catch block and continue execution if succeeded

Hi have the following method on a static class that I would like to retry 'x' number of times in case there is an specific exception type.
Right now, this is how it looks like.
public static void myMethod(DbContext context, ISettings settings)
{
try
{
RefreshDb(context, settings);
}
catch (Exception e)
{
throw new Exception("Error on method RefreshDb", e);
}
finally
{
// Do something here
}
}
What I want to do is to capture one specific exception type (in this case SqlException) and retry the call to RefreshDb few times over a timespan of 60 seconds. Once I capture the exception, how can I retry several times and also...
If it success then leave the catch block without throwing and continue the execution of my code (finally part in this case)
If it fails, throw a real exception.
.
public static void myMethod(DbContext context, ISettings settings)
{
try
{
RefreshDb(context, settings);
}
catch (SqlException e)
{
// Call RefreshDb here again.
}
catch (Exception e)
{
throw new Exception("Error on method RefreshDb", e);
}
finally
{
// Do something here
}
}

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);
}
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();
}
}
Maybe you can try this.
if(ex.Gettype() == typeof(SpecificException))

Catching exceptions from other methods

I have a class which contains several methods.
One of the methods runs in a while loop (MainMethod).
I call out to helper methods in the same class from MainMethod.
The Try Catch is contained within MainMethod where most of the execution occurs.
If an exception occurs in a helper method which doesn't contain a Try Catch, will it be caught further up? i.e. inside MainMethod which called the helper method.
class Class1
{
public MainMethod()
{
while (true)
{
try
{
// ...
// ...
// ...
HelperMethod();
// ...
// ...
}
catch (Exception e)
{
// Console.WriteLine(e.ToString());
// logger.log(e.ToString();
// throw e;
// ...
}
}
}
public HelperMethod()
{
// No Try Catch
// if (today == "tuesday") program explodes.
}
}
Thanks.
Yes. If a method has no try/catch block it will "bubble up" the stack and be caught by the next handler up the chain. If there is no handler, that's when your program terminates because an exception was "unhandled".
Yes it will. Something like this:
public class Helper
{
public void SomeMethod()
{
throw new InvalidCastException("I don't like this cast.");
}
public void SomeOtherMethod()
{
throw new ArgumentException("Your argument is invalid.");
}
}
public class Caller
{
public void CallHelper()
{
try
{
new Helper().SomeMethod();
}
catch (ArgumentException exception)
{
// Do something there
}
catch (Exception exception)
{
// Do something here
}
try
{
new Helper().SomeOtherMethod();
}
catch (ArgumentException exception)
{
// Do something there
}
catch (Exception exception)
{
// Do something here
}
}
}
Note that if caller application handles that specific type of exception, specific catch block will be called.
IMHO, it is good to handle specific exceptions that may be thrown by methods you call from your code. However, that also means that author of method you are calling created a decent document sharing exceptions that we need to expect from his code.

Why is custom exception changed to System.Exception when method invoked via method.invoke()?

I've written a custom exception AbortTestException, which is pretty simple:
class AbortTestException : Exception
{
public AbortTestException(string message)
: base(message) { }
}
Then I have a function that will throw it:
class Foo
{
public void Throws()
{
throw new AbortTestException("hi");
}
}
And Throws() gets called via method reference:
class Program
{
static void Main(string[] args)
{
Type myType = (typeof(Foo));
var method = myType.GetMethod("Throws");
try
{
method.Invoke(new Foo(), null);
}
catch (AbortTestException ex)
{
Console.WriteLine("AbortTestException");
}
catch (Exception ex)
{
Console.WriteLine("Exception");
}
}
}
However, something weird happens. Even though Throws rises an AbortTestException, the catch(Exception) block gets used (instead of the catch(AbortTestException) block). I tried putting the "throw new AbortTestException("hi")" portion in the try block itself, and verified that the correct catch block is used.
Is there some reason an exception would be re-cast when emitted via MethodInfo.invoke()?
http://msdn.microsoft.com/en-us/library/4k9x6bc0.aspx
Per the MSDN a TargetInvocationException is thrown if the invoked method or constructor throws an exception.
Did you check the nested Exception? My guess the original exception (AbortTest...) is wrapped in a nested one. The nested Exception will be in the InnerException property of the one which is caught by your code
Remember that catching Exception will match any exception that isn't caught by a more specific catch block before it:
Type myType = (typeof(Foo));
var method = myType.GetMethod("Throws");
try
{
try
{
method.Invoke(new Foo(), null);
}
catch (AbortTestException ex)
{
Console.WriteLine("AbortTestException");
}
catch(TargetInvocationException tie)
{
throw tie.InnerException;
}
catch (Exception ex)
{
Console.WriteLine("Exception");
}
}
catch(AbortTestException ate)
{
Console.WriteLine("AbortTestException after re-throw from TargetInvocationException");
}

How can I create my own exception?

This is the skeleton of the code I have:
if(CheckForSomething())
{
try
{
//do something
}
catch (UnauthorizedAccessException ex)
{
LogException(ex, item.server);
}
catch (Exception ex)
{
LogException(ex, item.server);
}
}
else
{
string error = "Some error";
//want to call LogException with error as argument
}
private static void LogException(Exception ex)
{
//write ex to one log file
// write ex.message to another log file
}
How can I call LogException method from the else block? I tried casting string as exception and creating an exception.
A better question imo is not how but why you would want to do this? Why not define two LogError overloads, one that takes an Exception and another that takes a string.
private static void LogError(Exception ex)
{
// write ex to one log file
// write ex.message to another log file
}
private static void LogError(string error)
{
//nothing to write to exception-specific log file
// write error info to another log file
}
It's not really advisable to generate your own Exception instance just for logging like this.
LogException(new Exception("some error"));
Have you considered factoring the // write ex.message to another log file behavior into a separate function and calling that with your desired string?
if(CheckForSomething())
{
try
{
// do something
}
catch (UnauthorizedAccessException ex)
{
LogException(ex);
}
catch (Exception ex) // Never do this. Do you know how to handle an OutOfMemoryException?
{
LogException(ex);
}
}
else
{
string error = "Some error";
LogMessage(error);
}
private static void LogException(Exception ex)
{
// write ex to one log file
LogMessage(ex.Message);
}
private static void LogMessage(string message)
{
// write message to another log file
}
you can also make you own exception class like this:
public class LogException: Exception
{
public LogException() : base()
{
}
public LogException(string message) : base(message)
{
}
}
Exception e = new Exception(error);
LogException ee = new LogException (Exception e);
throw ee;
Put this in the else block
You can do something like previously mentioned
LogException(new Exception("some error"));
But it might be better to create your own exception class:
class MyException : Exception
{
//...
}
then
LogException(new MyException());
Some good solutions so far. You don't want to create a custom exception just for logging someone else will have a WTF? moment reading your code.
The alternative is to just extract the message from exception for the log.... something like
if(CheckForSomething())
{
try
{
// do something
}
catch (UnauthorizedAccessException ex)
{
LogMessage(ex.Message);
}
}
else
{
LogMessage("Some Error!");
}
private static void LogMessage(string message)
{
//write message to log
}
Creating an exception for the sole purpose of passing it into a format handled by a method is a hack. It breaks the implicit understanding among programmers as to what exceptions are and what they are used for.

Categories

Resources