C# How to handle multiple exceptions which does all the same? - c#

In my code I have a method with multiple catch statements, which perform all the same statement. I'm not sure this is the correct way to implement this. How would you do this?
public void LoadControl(ControlDestination controlDestination, string filename, object parameter)
{
try
{
// Get filename with extension
string file = GetControlFileName(filename);
// Check file exists
if (!File.Exists(file))
throw new FileNotFoundException();
// Load control from file
Control control = LoadControl(filename);
// Check control extends BaseForm
if (control is BaseForm)
{
// Set current application on user control
((BaseForm)control).CurrentApplication = this;
((BaseForm)control).Parameter = parameter;
// Set web user control id
control.ID = filename;
Panel currentPanel = null;
switch (controlDestination)
{
case ControlDestination.Base:
// Set current panel to Base Content
currentPanel = pnlBaseContent;
// Set control in viewstate
this.BaseControl = filename;
break;
case ControlDestination.Menu:
// Set current panel to Menu Content
currentPanel = pnlMenuContent;
// Set control in ViewState
this.MenuBaseControl = filename;
break;
}
currentPanel.Controls.Clear();
currentPanel.Controls.Add(control);
UpdateMenuBasePanel();
UpdateBasePanel();
}
else
{
throw new IncorrectInheritanceException();
}
}
catch (FileNotFoundException e)
{
HandleException(e);
}
catch (ArgumentNullException e)
{
HandleException(e);
}
catch (HttpException e)
{
HandleException(e);
}
catch (IncorrectInheritanceException e)
{
HandleException(e);
}
}
This is how HandleException looks like:
private void HandleException(Exception exception)
{
// Load error control which shows big red cross
LoadControl(ControlDestination.Menu, "~/Controls/Error.ascx", null);
// Store error in database
DHS.Core.DhsLogDatabase.WriteError(exception.ToString());
// Show error in errorbox on master
Master.ShowAjaxError(this, new CommandEventArgs("ajaxError", exception.ToString()));
}

You are doing it right (you should catch only the exceptions you are going to handle and there is no way to catch more than one exception type in one single catch block), but as an alternative, you can just catch(Exception ex), check the exception type, and if it is not one that you expect just throw it again, something like this:
var exceptionTypes=new Type[] {
typeof(FileNotFoundException),
typeof(ArgumentNullException),
//...add other types here
};
catch(Exception ex) {
if(exceptionTypes.Contains(ex.GetType()) {
HandleException(ex);
} else {
throw;
}
}
UPDATE: With C# 6 (coming together with Visual Studio 2015) you are able to do the following instead:
catch(Exception ex) when (exceptionTypes.Contains(ex.GetType()) {
HandleException(ex);
}

I'd refactor as follows:-
public class Sample
{
public void LoadControl( ControlDestination controlDestination, string filename, object parameter )
{
HandleExceptions( HandleException, () =>
{
//.... your code
} );
}
private void HandleExceptions( Action<Exception> handler, Action code )
{
try
{
code();
}
catch ( FileNotFoundException e )
{
handler( e );
}
catch ( ArgumentNullException e )
{
handler( e );
}
catch ( HttpException e )
{
handler( e );
}
catch ( IncorrectInheritanceException e )
{
handler( e );
}
}
private void HandleException( Exception exception )
{
// ....
}
}
If I was using VB.NET, I'd use exception filters to do series of catches. But as we're using C#, the approach you have is the most efficient one possible rather than doing
private void HandleExceptions( Action<Exception> handler, Action code )
{
try
{
code();
}
catch ( Exception e )
{
if ( e is FileNotFoundException
|| e is ArgumentNullException
|| e is HttpException
|| e is IncorrectInheritanceException )
handler( e );
else
throw;
}
}

You can use generics for a much nicer solution as long as you don't mind using Lambda's too. I am not a fan of switching on type. I have used this code a few times, I find it comes in especially handy for service proxies in which you want to handle a number of exceptions in the same way. As has been stated above its always best to catch the right type of exception where possible.
The code works by specifying the exceptions as generic type arguments to the handle function. These specific types are then caught but passed to a generic handler as the base class. I didn't add a HandleAndThrow but this can be added as desired. Also change naming to your liking.
public static void Handle<T>(Action action, Action<T> handler)
where T : Exception
{
try
{
action();
}
catch (T exception)
{
handler(exception);
}
}
public static void Handle<T1, T2>(Action action, Action<Exception> handler)
where T1 : Exception
where T2 : Exception
{
try
{
action();
}
catch (T1 exception)
{
handler(exception);
}
catch (T2 exception)
{
handler(exception);
}
}
public static void Handle<T1, T2, T3>(Action action, Action<Exception> handler)
where T1 : Exception
where T2 : Exception
where T3 : Exception
{
try
{
action();
}
catch (T1 exception)
{
handler(exception);
}
catch (T2 exception)
{
handler(exception);
}
catch (T3 exception)
{
handler(exception);
}
}
public static void Handle<T1, T2, T3, T4>(Action action, Action<Exception> handler)
where T1 : Exception
where T2 : Exception
where T3 : Exception
where T4 : Exception
{
try
{
action();
}
catch (T1 exception)
{
handler(exception);
}
catch (T2 exception)
{
handler(exception);
}
catch (T3 exception)
{
handler(exception);
}
catch (T4 exception)
{
handler(exception);
}
}
}
public class Example
{
public void LoadControl()
{
Exceptions.Handle<FileNotFoundException, ArgumentNullException, NullReferenceException>(() => LoadControlCore(10), GenericExceptionHandler);
}
private void LoadControlCore(int myArguments)
{
//execute method as normal
}
public void GenericExceptionHandler(Exception e)
{
//do something
Debug.WriteLine(e.Message);
}
}

Write it like this:
try
{
// code that throws all sorts of exceptions
}
catch(Exception e)
{
HandleException(e);
}
edit: note that this is a direct answer to your question, not a comment on whether or not this is a recommended practice.
edit2: you can however test in your function if the type of e is a specific list of exceptions and if it's not, you can rethrow it. Exception handling performance is a non-issue since it's meant to be... exceptional in the first place.

I'm going to answer this is in a language-agnostic manner:
1. What you have done now is correct. Nothing wrong with it, except that it might get tedious if you do it many times.
2. Catch the most general form of exception that there is. Simply
catch(Exception e)
{
...
}
3. Maybe you want to only catch some exceptions, without catching all exceptions, which is what you would be doing if you just did #2.
Do what you did in #2, plus modify HandleException to only handle certain types of exceptions. This way you will only ever have to do type tem out once, and it is still more compact than above.
private void HandleException(Exception e) throws Excpetion
{
// Reject some types of exceptions
if (!((e is FileNotFoundException) ||
(e is ArgumentNullException) ||
(e is HttpException ) ||
(e is IncorrectInheritanceException )))
{
throw;
}
//Rest of code
...
}
Edit:
I see Konamiman has an improved version of this third option. I say go for that.

I would do it like this
public void LoadControl(ControlDestination controlDestination, string filename, object parameter)
{
try
{
// Get filename with extension
string file = GetControlFileName(filename);
// Check file exists
if (!File.Exists(file))
throw new FileNotFoundException();
// Load control from file
Control control = LoadControl(filename);
// Check control extends BaseForm
if (control is BaseForm)
{
// Set current application on user control
((BaseForm)control).CurrentApplication = this;
((BaseForm)control).Parameter = parameter;
// Set web user control id
control.ID = filename;
Panel currentPanel = null;
switch (controlDestination)
{
case ControlDestination.Base:
// Set current panel to Base Content
currentPanel = pnlBaseContent;
// Set control in viewstate
this.BaseControl = filename;
break;
case ControlDestination.Menu:
// Set current panel to Menu Content
currentPanel = pnlMenuContent;
// Set control in ViewState
this.MenuBaseControl = filename;
break;
}
currentPanel.Controls.Clear();
currentPanel.Controls.Add(control);
UpdateMenuBasePanel();
UpdateBasePanel();
}
else
{
throw new IncorrectInheritanceException();
}
}
catch (Exception e)
{
HandleException(e);
}
}
public void HandleException(Exception e)
{
if (e is FileNotFoundException
|| e is ArgumentNullException
|| e is HttpException
|| e is IncorrectInheritanceException)
{
// Load error control which shows big red cross
LoadControl(ControlDestination.Menu, "~/Controls/Error.ascx", null);
// Store error in database
DHS.Core.DhsLogDatabase.WriteError(exception.ToString());
// Show error in errorbox on master
Master.ShowAjaxError(this, new CommandEventArgs("ajaxError", exception.ToString()));
}
}

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

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

Good practice design pattern for Exception handling

I have exception handling code in every method for the below code for the bottom level methods
throw new Exception("The error that happens");
Is there any way I can avoid writing this code again and again in each method?
I am trying to write my own code and not using any log frameworks
private void TopLevelMethod()
{
try
{
SomeMethod();
}
catch (Exception ex)
{
// Log/report exception/display to user etc.
}
}
private void SomeMethod()
{
TestPartA();
TestPartB();
TestPartC();
TestPartD();
}
private void TestPartA()
{
// Do some testing...
try
{
if (somethingBadHappens)
{
throw new Exception("The error that happens");
}
}
catch (Exception)
{
// Cleanup here. If no cleanup is possible,
// do not catch the exception here, i.e.,
// try...catch would not be necessary in this method.
// Re-throw the original exception.
throw;
}
}
private void TestPartB()
{
// No need for try...catch because we can't do any cleanup for this method.
if (somethingshappens)
{
throw new Exception("The error that happens");
}
}
Only catch errors if you want to do something meaningful to them such as:
Wrapping the exception with a framework exception (e.g. SqlException. ADO.NET never passes you socket-level errors. It passes you a meaningful SQL error code)
Cleanup
Actually responding (e.g. retry, or insert default values)
Logging is almost never appropriate. The top level handler should log. Certainly not every method in the path should log. What a clutter for logs and for the code. Don't do that.
Simply don't swallow error information and let the error bubble out. That way there is no reason left to insert local logging code for errors everywhere.
If you prefer using Functional Programming like code style one way is to use callback error callbacks.
Example :
private void SomeMethod()
{
// do something
}
public bool Execute(Action act, Action<Exception> onErrorCallback)
{
var res = true;
try
{
act();
}
catch (Exception ex)
{
res = false;
onErrorCallback(ex);
}
return res;
}
And use Execute like this:
var successfull = true;
successfull &= Execute(SomeMethod, (ex) => { /* clean up */ });
successfull &= Execute(SomeMethod, (ex) => { /* clean up */ });
successfull &= Execute(SomeMethod, (ex) => { /* clean up */ });
successfull &= Execute(SomeMethod, (ex) => { /* clean up */ });
if (!successfull)
; // show user or something else
Graffito: Would you please give sample code example.Thankyou...
Your code refactored:
private void TopLevelMethod()
{
List<string> errors=new List<string>() ;
if (!SomeMethod(errors)) { /* Log/report errors/display to user etc. */ }
}
private bool SomeMethod(List<string> errors)
{
return TestPartA(errors) && TestPartB(errors) && TestPartC(errors) && TestPartD(errors);
}
private bool TestPartA(List<string> errors)
{
bool result = true ;
try
{
// Do some testing...
if (somethingBadHappens) { result=false; errors.Add("The error that happens"); }
}
catch (Exception ex) { errors.Add("Error in TestPartA: "+Ex.Exception.Message.ToString()) ; }
return result ;
}
private bool TestPartB(List<string> errors)
{
bool result = true ;
// Do some testing...
if (somethingBadHappens) { result = false ; errors.Add("The error that happens"); }
return result ;
}

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

Categories

Resources