问题
I'm pretty sure I already know the answer, but I'm still curious what the opinion is on handling an error within a Try,Catch,Finally block -- but when you're repeating yourself.
BTW - I'm not talking about User Input - but using that for an example because it is clear and short
Consider this bit of code...
try {
if (success) {
return someSuccessMessage;
}
else {
logError("User input not correct format");
return someErrorMessage; // repeats itself
}
}
catch (Exception ex) {
logError(ex.Message);
return someErrorMessage; // repeats itself
}
Say we have a function, that if it fails we want to return an error message because the exception is irrelevant -- our function did not succeed and the user doesn't need any additional detail.
I've always held the belief that if you can handle the error, avoid the exception -- since it isn't exceptional anymore, but I wondered the opinion about avoiding repeating yourself as well... You could do the following to avoid repeating yourself...
try {
if (success) {
return someSuccessMessage;
}
else {
throw new Exception("User input not correct format");
}
}
catch (Exception ex) {
logError(ex.Message);
return someErrorMessage;
}
This isn't the best example, but I was going for brevity to make the point of repeating code.
Exceptions are known to incur a performance penalty, but what are the thoughts about a situation like this?
回答1:
I question the separation of concerns here. Unless this function is part of the UI, it should not concern itself with error messages. It should be throwing exceptions instead. The caller of this method, if it's part of the UI, might want to produce an error message for display. If the caller were a web service, then it would want to produce a SOAP Fault, which might not use the same message (if it used any message at all).
I would also strongly suggest you log ex.ToString() and not ex.Message.
回答2:
IMO, an Exception should be thrown only when it is outside correctable situation. User inputting an incorrect format is known and shouldn't throw any Exception.
Treat Exception like it's catastrophic (data center on fire, earthquake, etc.). This way, you will see the difference between handling "regular error" and "Exception".
And yes, throwing and catching Exception cost a lot of performance, best is to avoid them.
回答3:
Extract the duplicated code out into a function, if you feel repeating yourself is a problem.
error_code_t fail (string message) {
logError(message);
return someErrorMessage;
}
// ...
try {
if (success) {
return someSuccessMessage;
}
else {
return fail("User input not correct format");
}
}
catch (Exception ex) {
return fail(ex.Message);
}
To be honest, I wouldn't worry about duplicating a couple of lines in the same function.
回答4:
In your case I would just return the error message (first example), because throwing an exception only to catch it 3 line below seems a bit odd.
A completely different thing is that I usually avoid returning error codes when possible - when I have an error situation, I through an exception and I catch it at the highest level possible. In this way the code is not littered with error handling everywhere and it is much easier to see the business logic. In your case (if you control it of course) the method that returns success could have thrown an exception in case of failure, and you wouldn't have to ask this question at all :)
It is true that Exceptions are expensive in C#, so they shouldn't be abused. Having said that, when you have an error, the 50ms or so hit in performance is usually irrelevant, so I tend to use them to keep the code clean.
回答5:
I'd agree with your logic in your example, however what exception do you think you are handling in your exception handling block vs your programmatic test? I suspect your exception handling block is really a "just in case something happened". So it really comes down to the exception handling rule.
If you don't need to handle an exception and its not across a distinct architectural boundary don't handle it. If its on the edge of a component boundary you might want to wrap it, placing the original in the inner exception.
If the functionality was being called from code you would either want to test the outcome with some status representation such as a response (HRESULT is a prime example of that. 0 == SUCCESS, != 0 == failure) or use exceptions.
Testing for programmatic errors or component failures is where you would use exceptions, if you are validating input from the user on a UI you might want to simply use logic and return status codes to help communicate the error to the user.
Finally think about localization too. If you ripple an English error message up through the system and present it to your French speaking user that wouldn't be useful and you don't want to start parsing strings at your UI to generate the French version, so exceptions are the way to go as long as the payload of the exception has enough information to generate a useful error message for the user to take corrective action.
Use status code where you have a tight coupling between the components and the calling component knows what to do in the different status conditions.
BTW You might want to log the stack trace as well as just the message using ToString() as it will give you more helpful information to resolve the issue.
HTH
回答6:
in that case, i'd actually say the try/catch is unnecessary, as your if is more than adequately handling your error
but the bottom one is the style i beleive should be used for more complicated situations
来源:https://stackoverflow.com/questions/1110069/throw-exception-vs-return-error-within-a-try-catch-finally