Tell me, please, throwing exceptions to the top is a normal practice?

Just now, in my project, I tried to do this (or rather made it into all the bottlenecks, especially where the work with the database is going), and it seemed to me convenient in terms of finding errors and debugging.

An example ( ignore the logic, only probros exceptions are interested ):

// Получение какого-либо значения из базы данных в виде object private object GetData_AsObject() { try { //тут идет получение данных из бд } catch (Exception e) { throw new Exception("Получение данных из " + tableName + "." + column); } } // Получение какого-либо значения из базы данных в виде string public string GetData_AsString() { try { if (GetData_AsObject() != null) return GetData_AsObject().ToString(); else return ""; } catch (Exception e) { throw new Exception(e.Message + " as string"); } } // Получение какого-либо значения из базы данных в виде int public int GetData_AsInt() { try { if (GetData_AsObject() != null) return int.Parse(GetData_AsObject().ToString()); else return 0; } catch (Exception e) { throw new Exception(e.Message + " as int"); } } 

And so the exception rises above. If somewhere in the code there is an exception handling, then it is executed and does not bother the user. If there is no processing, the user receives a complete error message.

But the code produces a lot of try-catch constructs. Is this considered to be littering?

  • (answer from noob) About c # I only know that this is a programming language. Recently, on a similar issue [article] [1] read (there about node.js) and there are a few tips on what to do if an error occurred (on the topic from the paragraph "Handling operational errors"). [1]: joyent.com/developers/node/design/errors - alvoro
  • Great question. - VladD
  • one
    @VladD, thanks. I just used to try to just write the code to work somehow, but now I'm starting to think about how I do it. These are the questions that began to appear ... - teanYCH

3 answers 3

Yes, it is quite normal practice. Most often, the code should not deal with exception handling - it usually does not have the appropriate authority to do so. In other words, it is not his business. He must either perform certain actions, or, having received an exception, forward it to the calling code, which can be trusted with this processing (which is a separate task, and according to Single responsibility , the first principle of SOLID , an object should not take on more than one duties) There are, of course, situations where the exception is a type of "normal situation", and the code that generated it can correctly handle it, but these are quite infrequent cases (and frankly, examples of such situations in my head somehow immediately float). Moreover, the question then arises whether to consider this situation as an exception.

If we talk about your example, then in any case, the logic of the reaction to the exception should be outside the responsibility of the code working with the database. It is unlikely that this code should take on the task of writing to the log or forming a human-readable error message for the end user.

ZY in spite of your words about “ignore the logic” , I won’t hold on and add: sincerely hope the next piece is not from the real code?

 if (GetData_AsObject() != null) return GetData_AsObject().ToString(); else return ""; 

ZY you kind of asked a few months ago a very similar question

  • no)) therefore I asked not to pay attention. hastily wrote just something was And so I try to separate the logic from the user interface. And all these exceptions go up to the visual part of the application and are already shown there, if not previously processed. Yes, there is also a question about exceptions, but then I did not know about the fact that they can be raised up. - teanYCH
  • this makes me happy. And you’re doing very dangerous things in it.> And all these exceptions go up to the visual part of the application and are already shown there, if you haven’t processed it so, why should you show the inside of your application to the user? - DreamChild
  • I process them. Just if an error occurs, in which the normal operation of the application can not be guaranteed, it is necessary to show it? - teanYCH
  • > It’s just that if an error occurs in which the normal operation of the application cannot be guaranteed, you must show it not to show the error, but some kind of human-readable information about this error. And complete the program afterwards - DreamChild
  • That's why I am doing a drop request with a description of the exception. So that the user could then explain what the problem is, and I could immediately understand where to dig. Another question - is it worth it to describe everything in such detail, is it not enough to describe the error that was received at the top level? - teanYCH

No, "throwing exceptions" in the form in which it is done in the code in question is not a "completely normal practice." Moreover, "forwarding" in this form greatly complicates debugging, making the localization of errors almost impossible.

The exception is worth catching in several cases:

  1. If the code that catches it, can recover after the exception - correctly continue working). For example, create a database if the connection to it fell with the error "the database does not exist." Or repeat the command if the first attempt fell with a connection error. The exception is caught and is not transferred above.

  2. If the code wants to log the exception on the layer boundary. The exception is caught, logged, and thrown through a throw; .

  3. If the code intentionally wants to hide the details of the exception, for example for security reasons. The original exception is logged, a new exception is thrown, without details.

  4. In the situation of the question - If the code can add additional information to the original exception. For example, add a tableName and column , as done in the question. An exception is caught, a new exception is thrown, with the mandatory transfer of the original exception as an innerException parameter:

 private object GetData_AsObject() { try { //тут идет получение данных из бд } catch (Exception e) { // передаем e вторым параметром в конструктор Exception throw new Exception("Получение данных из " + tableName + "." + column, e); } } 

And it is impossible to "throw" exceptions in the way it is done in the code from the question, because at the same time, the details of the original exception are completely lost, and the error message comes to the developer in the form of "somewhere something went wrong, but where exactly and what exactly - let them guess!"

    I think it makes no sense to throw Exception. At the top level, make try-catch and output not e.Message, but e.ToString () - there will be an exception type and all nested functions before the exception, and even a line of code is possible. And "forwarding" so you lose all the additional information.

    • Aha, and external code should know all types of internal exceptions? Or catch catch (Exception) ? - VladD
    • @VladD is a normal web backend practice. If the code cannot be recovered from the exception or add additional information, do not catch the exception. From above, there is usually a global daytitch that writes to the log and gives the client a 500 error. - PashaPash
    • @VladD is generally strange, the question describes the worst approach to processing - catching with the loss of setrays and details. And for him up there, too, will have to write catch (Exception). And this is called forwarding. And in the accepted reply, it says "yes, this is normal." And all this only because topadcast meant to "catch and throw a new exception without details" by forwarding - PashaPash