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