A well-designed app handles exceptions and errors to prevent app crashes. Below are some of the best practices:
1. Use try/catch/finally blocks to recover from errors or release resources
Use try/catch blocks around code that can potentially generate an exception and your code can recover from that exception.
2. Throw specific exceptions to make it easy for handling.
In catch blocks, always order exceptions from the most derived to the least derived.
3. Avoid return statement inside Finally block as it suppress the exception being thrown out from the method.
4. Avoid exceptions, Avoid returning Null, Handle common conditions
Handle common conditions without throwing exceptions. Design classes so that exceptions can be avoided. A class can provide methods or properties that enable you to avoid making a call that would trigger an exception. For example, a FileStream class provides methods that help determine whether the end of the file has been reached. These can be used to avoid the exception that is thrown if you read past the end of the file.
It may sound obvious to avoid exceptions. But many methods that throw an exception can be avoided by defensive programming.
One of the most common exceptions is NullReferenceException. When we return null, we are essentially creating work for ourselves and foisting problems upon our callers. All it takes is one missing null check to send an application spinning out of control. In some cases, you may want to allow null but forget to check for null. Here is an example that throws a NullReferenceException:
Address a = null; var city = a.City;
Accessing a throws an exception but play along and imagine that a is provided as a parameter. In case you want to allow a city with a null value, you can avoid the exception by using the null-conditional operator:
Address a = null; var city = a?.City;
By appending ? when accessing a, C# automatically handles the scenario where the address is null. In this case, the city variable will get the value null.
Do not use exceptions for the normal flow of control, if possible. Except for system failures and operations with potential race conditions, framework designers should design APIs so users can write code that does not throw exceptions. For example, you can provide a way to check preconditions before calling a member so users can write code that does not throw exceptions.
5. Throw exceptions instead of returning an error code. Exceptions ensure that failures do not go unnoticed because calling code didn't check a return code.
6. Consider the performance implications of throwing exceptions. Throw rates above 100 per second are likely to noticeably impact the performance of most applications.
7. Do document all exceptions thrown by publicly callable members because of a violation of the member contract (rather than a system failure) and treat them as part of your contract.
Exceptions that are a part of the contract should not change from one version to the next (i.e. exception type should not change, and new exceptions should not be added).
8. Place throw statements so that the stack trace will be helpful.
The stack trace begins at the statement where the exception is thrown and ends at the catch statement that catches the exception.
Catch (SpecificException specificException) { // ..... throw specificException; }
Catch (SpecificException specificException) { // ..... throw; }
class FileReader { private string fileName; public FileReader(string path) { fileName = path; } public byte[] Read(int bytes) { byte[] results = FileUtils.ReadFromFile(fileName, bytes); if (results == null) { throw NewFileIOException(); } return results; } FileReaderException NewFileIOException() { string description = "My NewFileIOException Description"; return new FileReaderException(description); } }
public void TransferFunds(Account from, Account to, decimal amount) { from.Withdrawal(amount); // If the deposit fails, the withdrawal shouldn't remain in effect. to.Deposit(amount); }
private static void TransferFunds(Account from, Account to, decimal amount) { string withdrawalTrxID = from.Withdrawal(amount); try { to.Deposit(amount); } catch { from.RollbackTransaction(withdrawalTrxID); throw; } }
try { service.SomeCall(); } catch { // Ignored }
0 comments:
Post a Comment