Mixing Errors and Exceptions in C #

I looked, but could not find a definitive answer to some of my exclusive questions, especially regarding C # best practices.

Perhaps they will always confuse me with the best way to use exceptions, I came across this article, which basically says "always use exceptions, never use error codes or properties" http://www.eggheadcafe.com/articles/20060612.asp . I will definitely buy this, but here is my dilemma:

I have a caller function that calls calllee. "callle" performs several different actions, each of which can cause the same type of exception. How do I pass the relevant information back to the “caller” about what the “caller” was doing during the exception?

I could add a new exception, as shown below, but I'm worried that I will corrupt the stack, which is bad:

//try to log in and get SomeException catch(SomeException ex) { throw new SomeException("Login failed", ex); } ... //try to send a file and get SomeException catch(SomeException ex) { throw new SomeException("Sending file failed", ex): } 

Thanks Mark

+6
source share
7 answers

In such scenarios, I usually insert a logger and log a specific error and restore the original exception:

 //try to log in and get SomeException catch(SomeException ex) { logger.LogError("Login failed"); throw; } ... //try to send a file and get SomeException catch(SomeException ex) { logger.LogError("Sending file failed"); throw; } 

throw; keep the original stack trace (unlike throw ex; which will create a new stack).

Edit

Depending on what your actual code is doing, it makes sense to actually split callee into several calls ( Login() , SendFile() , etc.), so caller performs separate steps instead of calling one big method that does everything. Then the caller finds out where he failed, and can affect him (maybe ask the user for different credentials)

+3
source

There is no single best practice to cover all scenarios in .Net. Anyone who says “always use exceptions” or “always uses error codes” is simply mistaken. Programs written in .Net are wide and complex to generalize to a hard and fast rule.

There are many cases where exceptions simply do not fit. For example, if I have very narrow loops looking for values ​​in Dictionary<TKey, TValue> , I would prefer TryGetValue over the index thrower. However, in other cases, I would prefer a throw if the data provided to me were concluded by contracts that were already on the map.

The best way to approach this decision is in each case. In general, I use only Exceptions if the situation is really exceptional. In fact, this cannot be predicted by the caller or the result of a call that clearly violates the contract. Examples

  • Unable to predict: File not found.
  • Contract breach: passing negative index to index
+7
source

The caller does not need to know what he called at the time of the exception. He should not know anything about how the call is made.

+5
source

'callee' performs several different actions, each of which can throw an exception of the same type.

I think this is a real criminal: callee should either throw another type of exception based on some kind of failure, or the same type of exception should contain enough additional information so that the caller can figure out how to handle this particular exception. Of course, if the caller is not designed to handle the exception at all, he should not be in the business to catch it in the first place.

+2
source

Why does the caller method take care of what callee does? Will another action be taken if there is a problem sending the file?

 try { callee(..); } catch (SomeException e) { if (e.Message == "Sending file failed") { // what would you do here? } } 

Exceptions should generally be exceptional. Your typical logical flow should not require to be thrown and broken. When they are thrown, this usually happens due to an error in your code *. Therefore, the main purpose of the exception:

  • to stop the flow of logic before the error does more damage, and
  • to provide information about the state of the system when an error occurs, so you can determine the source of the error.

Given this, you should generally only use exceptions if:

  • you plan to wrap the exception with additional data (as in your example) and throw a new exception, or
  • You know that there will be no further negative consequences from continuing your logical flow: you realize that the thing you tried to do is unsuccessful, and no matter how it failed, you are at peace with this. In these cases, you should always take the opportunity to register errors.

If there is a fairly common case of failure (for example, the user provided incorrect credentials), this should not be considered an exception. Rather, you should structure your callee method signature so that its return result provides all the details that caller should know about what went wrong.

* A notable exception is that something really unexpected happens, for example, if someone disconnected the network cable from the computer in the middle of a transaction.

+2
source

The Exception class provides a dictionary for adding additional data to an exception that is accessible through the Exception.Data property.

If all you want to do is pass the extra bits of information to the caller, then there is no reason to wrap the original exception and throw a new one. Instead, you can simply do:

 //try to log in and get SomeException catch(SomeException ex) { ex.Data.Add("action", "Login"); throw; } ... //try to send a file and get SomeException catch(SomeException ex) { ex.Data.Add("action", "Sending of file"); throw; } ... // somewhere further up the call stack catch(SomeException ex) { var action = ex.Data["action"] ?? "Unknown action"; Console.WriteLine("{0} failed.", action); // ... or whatever. } 

This way you can keep the original stack while you can still provide additional information to the user.

+1
source

If you really have a scenario where the caller needs to handle exceptions differently, then a typical strategy is to catch and wrap the main exception in the called.

You can either

  • wrap all detected main exceptions in one custom exception type, with a status code indicating which main exception was selected. This is common when using a vendor model design pattern. For example, Membership.CreateUser may raise a MembershipCreateUserException that has a status code to distinguish common causes of failure. Developer executives are expected to follow this pattern so that custom exception handling does not depend on vendor implementation.

  • or wrap each major exception type in a separate custom exception. This may be appropriate if you expect some callers to want to handle one of the exceptions (for example, the file could not be sent), but not the others (for example, login failure). Using different types of exceptions, the caller only needs to catch those that are of interest.

0
source

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


All Articles