The .Net framework try-catch implementation only allows you to catch types which inherit off the base class “System.Exception”. Why could this not have been an interface such as “System.IException”?
Use case
We use a custom base class in each API that inherits off System.Exception. This is only thrown once an exception has been logged and therefore we can easily avoid re-logging by something like:
try
{
// Do something.
}
catch (LoggedException)
{
// Already logged so just rethrow.
throw;
}
catch (Exception ex)
{
// TODO: Log exception.
throw new LoggedException("Failed doing something.", ex);
}
This is great until you want a custom exception that inherits off another system exception type such as System.FormatException
The only way to now handle both of these is to have two custom base types and duplicate every catch statement.
Refactoring
If the .net framework just simply looked for something such as System.IException then you could simply have a custom exception interface such as CompanyName.ILoggedException, inheriting System.IException which all your custom exception types implement. Therefore your new catch code would look something like:
try
{
// Do something.
}
catch (ILoggedException)
{
// Already logged so just rethrow.
throw;
}
catch (IException ex)
{
// TODO: Log exception.
throw new CustomException("Failed doing something.", ex);
}
Is there a practical reason the framework is implemented like this? Or would this be something to request in a future version of the .Net framework?
One possibly neater workaround that hasn’t been mentioned yet is to use extension methods. By harnessing the Exception.Data field, you could neatly discover from a single catch block whether the current exception has been logged yet, and take action as required. This would allow you to construct numerous different company specific exceptions (which are implicitly already logged).
Extension methods required:
Company exceptions take the following format, setting the IsLogged flag in the constructor:
try/catch usage:
I’d agree that this definitely isn’t as neat as the ability to match an exception based on an implemented interface, but I think the pattern is quite concise and readable. Having to remember to add the call to SetLogged() to each new company exception defined is a bit of a flaw though.