Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with interfaces that can throw just about anything?

Often I find myself in a situation where I have to deal with catching some exceptions thrown by implementers of an interface. This ususally gets problematic when the different implementations deal with completely different types of devices etc: depending on the implementation the amount and types of exceptions thrown vary greatly. Here's a typical example:

interface DataStream
{
  Data ReadNext();
}

class DeserializingFileDataStream : DataStream
{
  //this one does file operations + serialization,
  //so can throw eg IOException, SerializationException, InvalidOperationException, ...
}

class NetworkDataStream : DataStream
{
  //get data over tcp
  //so throws IOException, SocketException
}

class HardwareDeviceDataStream : DataStream
{
  //read from a custom hardware device implemented in unmanaged code
  //so throws mainly custom exceptions
}

Likely all these also throw ArgumentExceptions and so forth, but I'm not interested in catching those: in this case they would indicate programming errors. However I do not want the program to crash when a file is corrupted, a network cable is unplugged or the custom device goes berserk, so the other exceptions should be dealt with.

I already tried a couple of solutions but none of them I am particularly happy with, so the question is: is there some common practice/pattern to handle situations like these? Please be concrete and do not tell me to 'look at ELMAH'. Here's some things I used in the past:

  • catch( Exception ) well, it's obvious what the problems are
  • TryAndCatchDataStream( Action what, Action<Exception> errHandler ) method consisting of a try followed by a catch for any exception of interest from any implementation. Meaning it has to be updated when implementations change or are added/removed.
  • put a comment on the interface saying 'should only throw DataStreamExceptions' and in all implementations make sure this rule is followed by catching anything of interest and wrapping it in a DataStreamException, then throwing that. Not too bad, but adds noise to every implementation.

Then I have a second more general question about exception handling (don't think it's needed to make a seperate post for this): I have some cases where method A calls B which calls C which calls D, and D throws a SomeException yet the caller of A catches the exception. Isn't this a sign there is something wrong with the code? Because to be able to do this, the caller of A needs to know A will eventually call D. Unless A documents it can throw a SomeException; but in both cases it means that when updating a mere implementation detail of A (ie make it call something else than D), this change is visible to the users of A.

like image 902
stijn Avatar asked Feb 21 '23 16:02

stijn


1 Answers

There is no way to "know" what an unknown exception might be. All you can do is catch the exceptions you know about, and perhaps log the ones you don't and rethrow them.

You could catch Exception, then call a method in a seperate assembly that determines what to do with the excpetion. Then you could update the assembly as needed without having to update the rest of the code.

Regarding your second question, A needs to document any exception that can bubble up from it, that includes exceptions thrown by dependant objects. B needs to document the exceptions it throws, so A can know about them, etc.. etc..

If you change A to do something that causes a change in the exceptions thrown, then you have to change the documentation. From the calling applications perspective, all it knows about is A. A can be doing anything, and the calling app doesn't care if it's a B, C or D. A is responsible for whatever gets bubbled up to the caller.

Think of it like this. Suppose you hired a construction company to build you a house. They, in turn, hire sub-contractors. Those Sub-Contracots might hire their own labor. If the bottom level laborors screw up, ultimate the contractor you hired is at fault, regardless of whether it was some other company that hired them. You don't care, you just want your house built to specifications, adn the construction company is respoonsible for that.

like image 108
Erik Funkenbusch Avatar answered Apr 26 '23 10:04

Erik Funkenbusch