Reputation: 744
I have a monitor class which monitors a device and reports if that device successfully receives usable data. This can happen anytime.
A client creates its own monitor by passing delegates, starts it and waits for either the successfully read data or a kind of domain specific exception type (one base exception type)
What would be the idiomatic way of throwing subtypes of the base exception type and enable the client to respond to each subtype individually?
public class MyMonitor
{
private SuccessHandler _successHandler;
private ErrorHandler _errorHandler;
public delegate void SuccessHandler(MyDTO result);
public delegate void ErrorHandler(MyBaseException exception);
public MyMonitor(SuccessHandler successHandler, ErrorHandler errorHandler) {
_successHandler = successHandler;
_errorHandler = errorHandler;
}
public void start() {
try {
_successHandler(new MyDTP().doSomethingRisky());
} catch(Exception e) {
_errorHandler(e);
}
}
}
public class Client {
static void Main(string[] args) {
MyMonitor monitor = new MyMonitor(new MyMonitor.SuccessHandler(handleSuccess), new MyMonitor.ErrorHandler(handleException));
monitor.start();
}
static void handleSuccess(MyDTO result) {
// do something with result
}
static void handleException(MyBaseException e) {
try {
throw e;
} catch(UserException mbe) {
// present message to user
} catch(DataNotFoundException se) {
// log error and show generic error message
} catch(UnexpectedException ue) {
// log error and try to hide it from the user
}
}
}
Upvotes: 1
Views: 375
Reputation: 1965
So, why don't you handle the exceptions in your main instead of the monitor-class?
If that isn't an option, you have (at least) two alternatives:
static void handleException(MyBaseException e)
{
if (e is UserException)
{
// present message to user
}
else if (e is DataNotFoundException)
{
// log error and show generic error message
}
elseif (e is UnexpectedException)
{
// log error and try to hide it from the user
}
else
{
// might want to rethrow the exception, do a general handling,...
}
}
That way you don't have to rethrow the exception, just to catch it again. But this can get ugly if you have many subtypes to handle and here is where multidispatch comes in.
static void HandleException(MyBaseException e)
{
HandleSubException((dynamic)e);
}
static void HandleSubException(MyBaseException e)
{
// might want to rethrow the exception, do a general handling,...
}
static void HandleSubException(DataNotFoundExceptione)
{
// log error and show generic error message
}
static void HandleSubException(UnexpectedException e)
{
// log error and try to hide it from the user
}
static void HandleSubException(UserExceptione)
{
// present message to user
}
Now you can tend to each exception in its own method and is much easier to read and maintain. Having said that, I'm not entirely sure if this falls under best practice.
Upvotes: 2