Generic exception handlers: clever idea or bad idea
-
One difficulty with the normal exception system is that while it allows applications to use catch exceptions from which other exceptions are inherited, the normal exception hierarchy is based upon what type of problem occurred, rather than upon what the problem 'means'. An TimeoutException that occurs in one circumstance should probably be handled totally differently from one that occurs in another. Although .Net allows one to define a custom hierarchy for one's own exceptions, each exception class needs to repeat the code for the four standard New() methods, and so creating a significant number of classes can be a nuisance. One approach which would seem to hold some promise would be for an application to express its own exceptions using generic classes, something like:
Class GenEx
Inherits Exception
... New() methods here
End ClassClass GenEx(of T)
Inherits GenEx
... New() methods here
End ClassClass GenEx(of T, U)
Inherits GenEx(of T)
... New() methods here
End ClassClass GenEx(of T, U, V)
Inherits GenEx(of T, U)
... New() methods here
End Classetc. if more nesting is desired.
Then if an object of type MyThing wants to throw an exception for a timeout condition, it can throw a New GenEx(of MyThing, TimeoutException) which can be caught by a Catch of either GenEx, GenEx(of MyThing), or GenEx(of MyThing, TimeoutException). Things get a little clunky if MyThing is itself an inherited class; catch statements for GenEx(of MyThingsParent) won't catch a throw of type GenEx(of MyThing). In designing the throw statements for MyThing, however, one could throw a GenEx(of MyThingsParent, MyThing, TimeoutException) [though that would unfortunately only get snagged by a Catch of GenEx(of MyThingsParent) and not one of GenEx(of MyThingsParent, TimeoutException)] or a GenEx(of MyThingsParent, MyThing, TimeoutException) [ignoring the actual type of MyThing]. Has anyone else tried anything at all similar to this approach? With what effects (good or bad)? Pro: it would facilitate a more useful exception hierarchy based upon the type of object trying to do something than upon the nature of the result. Con: unless one had a procedure for cataloging the exceptions one was actually using, it could turn into a real mess. Any thoughts?
-
One difficulty with the normal exception system is that while it allows applications to use catch exceptions from which other exceptions are inherited, the normal exception hierarchy is based upon what type of problem occurred, rather than upon what the problem 'means'. An TimeoutException that occurs in one circumstance should probably be handled totally differently from one that occurs in another. Although .Net allows one to define a custom hierarchy for one's own exceptions, each exception class needs to repeat the code for the four standard New() methods, and so creating a significant number of classes can be a nuisance. One approach which would seem to hold some promise would be for an application to express its own exceptions using generic classes, something like:
Class GenEx
Inherits Exception
... New() methods here
End ClassClass GenEx(of T)
Inherits GenEx
... New() methods here
End ClassClass GenEx(of T, U)
Inherits GenEx(of T)
... New() methods here
End ClassClass GenEx(of T, U, V)
Inherits GenEx(of T, U)
... New() methods here
End Classetc. if more nesting is desired.
Then if an object of type MyThing wants to throw an exception for a timeout condition, it can throw a New GenEx(of MyThing, TimeoutException) which can be caught by a Catch of either GenEx, GenEx(of MyThing), or GenEx(of MyThing, TimeoutException). Things get a little clunky if MyThing is itself an inherited class; catch statements for GenEx(of MyThingsParent) won't catch a throw of type GenEx(of MyThing). In designing the throw statements for MyThing, however, one could throw a GenEx(of MyThingsParent, MyThing, TimeoutException) [though that would unfortunately only get snagged by a Catch of GenEx(of MyThingsParent) and not one of GenEx(of MyThingsParent, TimeoutException)] or a GenEx(of MyThingsParent, MyThing, TimeoutException) [ignoring the actual type of MyThing]. Has anyone else tried anything at all similar to this approach? With what effects (good or bad)? Pro: it would facilitate a more useful exception hierarchy based upon the type of object trying to do something than upon the nature of the result. Con: unless one had a procedure for cataloging the exceptions one was actually using, it could turn into a real mess. Any thoughts?
supercat9 wrote:
clever idea or bad idea
Or possibly both. :-D I dunno, I just tried the syntax in C# and got no errors, so it seems valid. I just haven't yet thought of a use for it. If you could come up with a situation in which to use it, you may be more convincing.
-
supercat9 wrote:
clever idea or bad idea
Or possibly both. :-D I dunno, I just tried the syntax in C# and got no errors, so it seems valid. I just haven't yet thought of a use for it. If you could come up with a situation in which to use it, you may be more convincing.
I just haven't yet thought of a use for it. Well, one use is to reduce the amount of copy/pasted code for custom exceptions. Not in and of itself sufficient reason to use a new pattern, though if using a wider range of exceptions is helpful and the reduced copy/paste requirement would encourages such practices, that could be a good thing. More generally, it seems to me that there are many situations where a routine's caller will sometimes want to know the specifics of something that went wrong, and others where the caller's concern is simply whether or not it worked. For example, if I send a request for information to another machine and I don't get a valid reply, there are a number of things that could have gone wrong (note that the protocol is designed for communicating with an embeded system via serial or TCP, so it includes its own sequence numbers, checksums, etc. to allow for the possibility of dropped or garbled bytes):
- Connection attempt failed at transport layer
- Connection died at transport layer
- No response received
- Garbage packet received
- Valid-seeming packet received, but with wrong sequence number
- Valid packet received indicating remote end received out-of-sequence packet
- Valid packet: "Command unknown"
- Valid packet: "Credentials refused"
- Valid packet: "Command invalid in this context"
- Valid packet, but not the expected type
- Valid packet, but not the expected length
In some cases, if a command/reply exchange fails, it won't really matter why, and it will make sense to just catch a generic 'something went wrong while exchanging packets' exception. In others, different exception causes should be handled differently. At that level (send/receive one packet), basic inheritance would suffice, though copying/pasting code for all the different exceptions would be annoying. At a higher level, though, the effective meaning of the above errors may depend upon what the system was doing when it occurred. If certain exceptions happen on certain commands, for example, the system should probably try to re-establish synchronization with the remote machine as soon as possible. In other case, that wouldn't be helpful. Thinking about it, perhaps the best trick wouldn't be to use nested generic exceptions, but rather to take advantage of the 'When' clause in VB.net; if a custom exception class contains an integer with a bitmask enumeration type, then an exception handler could
-
I just haven't yet thought of a use for it. Well, one use is to reduce the amount of copy/pasted code for custom exceptions. Not in and of itself sufficient reason to use a new pattern, though if using a wider range of exceptions is helpful and the reduced copy/paste requirement would encourages such practices, that could be a good thing. More generally, it seems to me that there are many situations where a routine's caller will sometimes want to know the specifics of something that went wrong, and others where the caller's concern is simply whether or not it worked. For example, if I send a request for information to another machine and I don't get a valid reply, there are a number of things that could have gone wrong (note that the protocol is designed for communicating with an embeded system via serial or TCP, so it includes its own sequence numbers, checksums, etc. to allow for the possibility of dropped or garbled bytes):
- Connection attempt failed at transport layer
- Connection died at transport layer
- No response received
- Garbage packet received
- Valid-seeming packet received, but with wrong sequence number
- Valid packet received indicating remote end received out-of-sequence packet
- Valid packet: "Command unknown"
- Valid packet: "Credentials refused"
- Valid packet: "Command invalid in this context"
- Valid packet, but not the expected type
- Valid packet, but not the expected length
In some cases, if a command/reply exchange fails, it won't really matter why, and it will make sense to just catch a generic 'something went wrong while exchanging packets' exception. In others, different exception causes should be handled differently. At that level (send/receive one packet), basic inheritance would suffice, though copying/pasting code for all the different exceptions would be annoying. At a higher level, though, the effective meaning of the above errors may depend upon what the system was doing when it occurred. If certain exceptions happen on certain commands, for example, the system should probably try to re-establish synchronization with the remote machine as soon as possible. In other case, that wouldn't be helpful. Thinking about it, perhaps the best trick wouldn't be to use nested generic exceptions, but rather to take advantage of the 'When' clause in VB.net; if a custom exception class contains an integer with a bitmask enumeration type, then an exception handler could
In this particular example, I would use one or maybe two exceptions (one for 1-4, another for 5-10) with an extra field that can store an enum value defining the error that occurred. Unless you find yourself with situations where you want to catch one type of error and not another, there's no need to make different exception types. Even then, you could catch the single exception type, handle it if you can, and rethrow it if you cannot.
-
In this particular example, I would use one or maybe two exceptions (one for 1-4, another for 5-10) with an extra field that can store an enum value defining the error that occurred. Unless you find yourself with situations where you want to catch one type of error and not another, there's no need to make different exception types. Even then, you could catch the single exception type, handle it if you can, and rethrow it if you cannot.
I think this entire thread is an case for "everybody prod microsoft into putting the CLR exception filtering support into c#" :P
Mark Churchill Director, Dunn & Churchill Pty Ltd Free Download: Diamond Binding: The simple, powerful, reliable, and effective data layer toolkit for Visual Studio.
Entanglar: .Net game engine featuring automatic networking and powerful HLSL gfx binding. -
One difficulty with the normal exception system is that while it allows applications to use catch exceptions from which other exceptions are inherited, the normal exception hierarchy is based upon what type of problem occurred, rather than upon what the problem 'means'. An TimeoutException that occurs in one circumstance should probably be handled totally differently from one that occurs in another. Although .Net allows one to define a custom hierarchy for one's own exceptions, each exception class needs to repeat the code for the four standard New() methods, and so creating a significant number of classes can be a nuisance. One approach which would seem to hold some promise would be for an application to express its own exceptions using generic classes, something like:
Class GenEx
Inherits Exception
... New() methods here
End ClassClass GenEx(of T)
Inherits GenEx
... New() methods here
End ClassClass GenEx(of T, U)
Inherits GenEx(of T)
... New() methods here
End ClassClass GenEx(of T, U, V)
Inherits GenEx(of T, U)
... New() methods here
End Classetc. if more nesting is desired.
Then if an object of type MyThing wants to throw an exception for a timeout condition, it can throw a New GenEx(of MyThing, TimeoutException) which can be caught by a Catch of either GenEx, GenEx(of MyThing), or GenEx(of MyThing, TimeoutException). Things get a little clunky if MyThing is itself an inherited class; catch statements for GenEx(of MyThingsParent) won't catch a throw of type GenEx(of MyThing). In designing the throw statements for MyThing, however, one could throw a GenEx(of MyThingsParent, MyThing, TimeoutException) [though that would unfortunately only get snagged by a Catch of GenEx(of MyThingsParent) and not one of GenEx(of MyThingsParent, TimeoutException)] or a GenEx(of MyThingsParent, MyThing, TimeoutException) [ignoring the actual type of MyThing]. Has anyone else tried anything at all similar to this approach? With what effects (good or bad)? Pro: it would facilitate a more useful exception hierarchy based upon the type of object trying to do something than upon the nature of the result. Con: unless one had a procedure for cataloging the exceptions one was actually using, it could turn into a real mess. Any thoughts?
supercat9 wrote:
clever idea or bad idea
A finer blend of both. For some cases, it wouldn't be meaningful to have unneeded exception clauses and for code readability purposes, you can club them into generic.
Vasudevan Deepak Kumar Personal Homepage
Tech Gossips
The woods are lovely, dark and deep, But I have promises to keep, And miles to go before I sleep, And miles to go before I sleep!