Try/Catch: Moving catches to separate function? - c#

try
{
myInfo = getMyInfoFromAPI(); //stubbed
}
catch (JsonSerializationException exception)
{
// special handling and logging
}
catch (Exception ex)
{
// special handling and logging
}
This kind of code in my opinion is quite long and could be broken into separate functions. Is it possible to move the catches each into finally block where it can see if there is anything to catch?
try
{
myInfo = getMyInfoFromAPI(); //stubbed
}
finally {
handleJsonException();
handleException();
}
public void handleJsonException() {
catch (JsonSerializationException exception)
{
// special handling and logging
}
}
public void handleException() {
catch (Exception exception)
{
// special handling and logging
}
}
Is this possible or even good practice? The reason I'm curious if we can move the catches into new functions is the lines of code can become quite long and unreadable for one given function.

finally cannot catch exception.
I recommend to use like this.
try
{
myInfo = getMyInfoFromAPI(); //stubbed
}
catch (JsonSerializationException ex)
{
handleJsonException(ex);
}
catch (Exception ex)
{
handleException(ex);
}
public void handleJsonException(JsonSerializationException ex) {
// special handling and logging
}
public void handleException(Exception ex) {
// special handling and logging
}

The purpose of finally is not to catch exception, it will be called irrespective of Exception is thrown or not, use finally for clean-up purposes (disposing of objects).
If you want to make the catch block modular based on the Exception type then you can do something like -
try
{
// Some Code
}
catch (Exception exception)
{
if (exception is InvalidOperationException operationException)
{
MethodCall(operationException);
}
else if (exception is JsonSerializationException jsonSerializationException)
{
AnotherMethodCall(jsonSerializationException);
}
// If want to throw the exception further.
throw;
}

Related

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

Proper way to rethrow an exception

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

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.

Parameters to Catch?

Is it possible to pass parameters to a catch block?
Here is some example code:
try
{
myTextBox.Text = "Imagine, that could fail";
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
Can I pass the Textbox (myTextBox) now to my catch block if it would fail? smth. like that:
try
{
myTextBox.Text = "Imagine, that could fail";
}
catch (Exception e, TextBox textBox)
{
textBox.BorderBrush = Colors.Red;
MessageBox.Show(e.Message);
}
How I would do that?
No it's not possible by standart.
What you can do, is to define your custom exception and assign parameters there, for example:
public class MyCustomException : Exception
{
public string SomeAdditionalText {get;set;}
....
//any other properties
...
}
and inside the method which raises an exception raise your own MyCustomException
You only catch a single thing, which in C# must be an Exception. So not directly. However! If the Exception were, say, a custom SomethingSpecificException, then you could make that information available on e.SomeProperty.
public class SomethingSpecificException : Exception {
public Control SomeProperty {get;private set;}
public SomethingSpecificException(string message, Control control)
: base(message)
{
SomeProperty = control;
}
...
}
Then at some point you could:
throw new SomethingSpecificException("things went ill", ctrl);
and
catch(SomethingSpecificException ex) {
var ctrl = ex.SomeProperty;
....
}
don't know what you want to achieve, but in the catch block you can access any UI element, as you do in the try block. So for me there is no point of defining an additional parameter in the catch block.
Next to the possibility to use custom exception to distinguish what's going on:
try
{
myClass.DoSomethingThatCouldThrow();
myClass.DoSomethingThatThrowsSomethingElse();
myClass.DoAnotherThingWithAThirdExceptionType();
}
catch(FirstSpecialException ex)
{
// Do something if first fails...
}
catch(SecondSpecialException ex)
{
// Do something if second fails...
}
You could also put every statement into its own exception block. This would make your code quite lengthly, but is maybe the only possibility if you can't change the class to throw any special exception.
try
{
myClass.DoSomethingThatCouldThrow();
}
catch(InvalidOperationException ex)
{
// Do something if it fails...
}
try
{
myClass.DoSomethingThatCouldThrow();
}
catch(InvalidOperationException ex)
{
// Do something if it fails...
}
try
{
myClass.DoAnotherThingWithAThirdExceptionType();
}
catch(InvalidOperationException ex)
{
// Do something if it fails...
}
Due to the fact, that this last, looks a little bit like repetitive code, we could maybe put it into some method with the following body:
public void TryCatch<ExceptionT>(Action tryMethod, Action<ExceptionT> catchMethod)
where ExceptionT : Exception
{
// ToDo: ArgumentChecking!
try
{
tryMethod();
}
catch(ExceptionT ex)
{
catchMethod(ex);
}
}
Which could you then call with:
TryCatch<InvalidOperationException>(
() => myClass.DoSomething(),
(ex) => Console.WriteLine(ex.Message));

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