Should I catch exceptions in my method for "purely documenting" purposes?

Should I catch exceptions in my method for the purpose of "purely documenting", thus encapsulating the documentation of errors within the method itself, or is this the responsibility of the caller?

Suppose in my EncryptPackage() method, including frameworks, I call many other methods that could potentially cause many exceptions. I wrap everything in using blocks, so there is no need to catch exceptions for cleaning (or I use try / finally for cleaning). Should I catch the exception anyway and provide details about the context of this method, or does it depend on the caller’s method?

Here is one case:

 [Serializable] class TestClassException : Exception { public TestClassException() : base() { } public TestClassException(string message) : base(message) { } public TestClassException(string message, Exception innerException) : base(message, innerException) { } } class TestClass { public TestClass() { } public void EncryptPackage() { try { DoSomething(); DoAnotherThing(); } catch (Exception ex) { throw new TestClassException("Error occurred during package encryption", ex); } } } class ConsumerExample { public ConsumerExample() { } public void DoSomeStuff() { TestClass testClass = new TestClass(); try { testClass.EncryptPackage(); } catch (TestClassException ex) { System.Windows.Forms.MessageBox.Show(ex.ToString()); } } } 

In this code, notice how the EncryptPackage() method detects all possible exceptions, simply "decorates the error text", with the text "Error while processing the package." EncryptPackage() here encapsulates the error description logic.

And here is another technique:

 class TestClass2 { public TestClass2() { } public void EncryptPackage() { DoSomething(); DoAnotherThing(); } } class ConsumerExample2 { public ConsumerExample2() { } public void DoSomeStuff() { TestClass testClass = new TestClass(); try { testClass.EncryptPackage(); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show("Error occurred during package encryption.\r\n\r\n" + ex.ToString()); } } } 

In this example, EncryptPackage() will not catch anything, because the calling document still documents an error case with the message "An error occurred while encrypting the packet. \ R \ n \ r \ n".

Please note that this is a very simplified example, in the real world there will be many hierarchical classes, and exceptions will be propagated through the stack of a long call, so which method of catching exceptions is preferred? The second approach seems to be “cleaner”, because the exception is handled in the layer where some “actual processing” will be performed (for example, display to the user). The call stack information will be stored in the exception object, so it will technically be possible to find out exactly where the exception was selected. But ... this does not look like a “good documentation” as the first approach, where each level of abstraction adds its own description to the error, storing the previous exception in the innerException member. In this case, when the execution leaves the TestClass layer, it already contains a detailed description of the error that occurred in this class. Thus, it becomes the best encapsulation of error handling logic.

Which one to use?

+4
source share
4 answers

As with @Sjoerd above, translate the exceptions so that they are at the same level of abstraction. In your case, EncryptPackage should throw any lower-level exceptions that DO NOT raise.

It is said that lower level exceptions were from the database level (say, DBException). Will the caller expect an understanding of DBException? Answer NO: the caller wants to include a package, not a DBException. Lower level exceptions must be chained to the INSIDE circuit to exclude a higher level for debugging purposes.

Finally, I know that TestClassException is an example, but make sure the exception class clearly describes the problem: I personally don't like the soft, general exception classes (besides making a common base class for other exceptions).

+1
source

Effective Java has a chapter :

Higher levels should catch exceptions at the lower level and, in their place, eliminate exceptions that can be explained in terms of a higher level of abstraction. This idiom is known as exception translation.

+4
source

I prefer your second example, mainly because it can significantly reduce the amount of error handling code that you should write, especially if you write custom exceptions - in the first example, you can get many custom exception classes that do not bring much benefit (you there is already a call stack to tell you where the exception came from).

You might think that it would be nice to have a more descriptive error message, but who benefits? End user? If you even show exception messages to your user (and what language are you going to use)? In most cases, the user just needs to know that there was an internal error, and they should refuse (restart) or try again. Do you show developer benefits? You will probably end up exploring the call stack anyway with the source code in front of you, so you don't need a more detailed message, you can see for yourself what the code is doing at that moment.

This is not a complicated and quick rule. In most cases, I deal only with exceptions at the top level, where I register them and report an error to the user. If you report an exception directly to the user, then often the original exception does not benefit from the translation, for example, if you try to open a file that does not exist, then the System.IO.FileNotFoundException exception is quite obvious, so translate it to something else? Do you really want to make the same proposition ("I know better than the author of the library, so I'm going to translate their carefully crafted exceptions") for all exceptions from the exceptions? I will only catch the exceptions below if I want to recover from them (as a rule, this is impossible), or, very rarely, I want to translate them into a more descriptive exception.

In a multi-tier architecture, it might make sense to translate exceptions between levels, such as catch exceptions that go from the data access layer, into a form suitable for the application layer and similarly between the application layer and the user interface, but I don’t know if you work in this type of system.

If you want to document your exceptions, you should use the exception tag in the xml documentation for this method. This can then be used for general help files from the documentation, for example using SandCastle .

+2
source

You should try / catch in few, easily distinguishable situations:

  • any method that can be called "externally", for example, the entry point to the application, user interface events, multithreaded calls, and others. Put some sort of log output or message on every catch that you have. This will prevent your application from crashing (for the most part) and provide you or the user with some feedback on how to fix the problem.

  • when you really can handle the exception. This means that your application can, for example, select an additional URL for the database or server, apply other processing, etc.

  • when you want to prevent something optional in order to ruin the main workflow, for example, if you did not delete the temp file, this should not cause your process to crash.

  • there are probably some other places where you will need try / catch, but they should be rare

Always combine error handling with a decent way of logging and / or exchanging messages with the user, do not let exceptions be excluded due to the fact that you receive applications and feel bad for “for no apparent reason” - at least the reason should be obvious.

Also - do not use exceptions to control your workflow. There really shouldn't be any “throws” unless there is another way to do something.

0
source

Source: https://habr.com/ru/post/1437127/


All Articles