When to use exception or when to use message? [closed] - c#

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I am wondering what is the best way to warn about a data that a user has to provide is missing or wrong.
Exceptions, for me, are when there are something exceptional that I can't control, for example, if i try to write a file, there is no permissions or the hard drive is full. If I am querying database, the database is down or the LAN connections doesn't work... etc.
But if it is because a user doesn't provide a needed information or it is incorrect, this is something that I have control over it, so from some point of view, it is not an exception, because it depends on me. But if I don't use exceptions, to warn the user, I have to show a dialog, so the code it is much more complex if I have considerate all the possibilities.
For example, with exceptions I could have this code:
try
{
if(esData1Correct() == false) throw new Exception("Data1 incorrect");
if(esData2Correct() == false) throw new Exception("Data2 incorrect");
if(esData3Correct() == false) throw new Exception("Data3 incorrect");
// All is correct, I continue with the code.
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
However, if I want to use dialogs, the code that I should use, or the code that I think I would have to use is something like that:
if(esData1Correct() == false)
{
MessageBox.Show("Data1 is incorrect.");
}
else if(esData2Correct() == false)
{
MessageBox.Show("Data2 is incorrect.")
}
else if(esData3Correct() == false)
{
MessageBox.Show("Data3 is incorrect.")
}
else
{
// All is correct, so I can continue with my code.
}
So which code is more correct, to use exceptions or messages to warn the user the information is not correct? Are there another better options?
Thanks.

So which code is more correct, to use exceptions or messsages to warn
the user the information is not correct? Are there another better
options?
Neither is more correct and they both show the message to the user with or without the exceptions; mission accomplished. Indeed, you wouldn't warn the user with an exception per say so it's transparent to them anyway unless you plan to dump the stack trace to the UI (don't!!). There are things to consider when using exceptions and you certainly don't want to use them everywhere for everything but it's not wrong to use them for validation failures. Read on for more.
Exceptions are meant for exceptional conditions but what constitutes an exceptional condition varies. Linq's First, for example, will throw an exception if the source or predicate is null, the source is empty, or there's no element that matches the predicate. They could have just returned null but they chose to instead push the responsibility onto the caller to get it right. To me, that's a reasonable use of exceptions where it wasn't exactly necessary; a collection not containing an element that matches a predicate happens all the time so it's not exactly exceptional. And it's not uncommon to see ArgumentExceptions and ArgumentNullExceptions used in similar cases as yours; that's probably how I'd do it absent a more sophisticated approach.
But, first thing's first. I know this is an example but there are some pain-points that need to be addressed before worrying about which approach is more appropriate.
The following is objectively stinky:
try
{
if(esData1Correct() == false) throw new Exception("Data1 incorrect");
if(esData2Correct() == false) throw new Exception("Data2 incorrect");
if(esData3Correct() == false) throw new Exception("Data3 incorrect");
//All is corerct, I continue with the code.
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
Here, the code is using exceptions as control flow. You know something is wrong and can handle it at that point but instead throw and catch an exception to show the message; not good.
Also, don't throw or catch System.Exception. Exceptions, if used, should be specific enough to do something meaningful about it based on the context. Again, it's a small example but this sort of thing is everywhere in naive code.
Having said that, the first example would change and would not catch the ArgumentException if thrown. Let the caller catch the errors as they're the ones creating the exceptional condition; in other words, pull the validation out. The caller should also worry about what to do about it. As it is now, the validation code is tightly coupled to a message box which makes it difficult to reuse.
public Foo Bar(...)
{
// A better way may be to validate them all and return a message
// that aggregates all incorrect data back...
if(!esData1Correct()) throw new ArgumentException("Data1 incorrect");
if(!esData2Correct()) throw new ArgumentException("Data2 incorrect");
if(!esData3Correct()) throw new ArgumentException("Data3 incorrect");
// more ?
}
Given we're willing to remove the coupling to the message box, the second example doesn't really do what we want so instead create a ValidationResult class that can help you build a meaningful message to the user.

I prefer second option, since it uses less resources, and is less complex.
Exception throwing should be used when you want to delegate exception handling to client-module which triggers your code and thus knows more about context in which your code is executed. There is not much sense in handling exception inside same method which throws it. You are right about that - in this example you know everything about what went wrong, and there is no need for exceptions, you just detect error and notify user about it, and that's all.

The rule is generally: Exceptions should be exceptional.
A few examples:
var username = input.Text;
if (string.IsEmptyOrNull())
{
// Give the user a chance to correct the input, this should not be an exception!
}
However, in an API, you might have a method that accepts a user object parameter:
var user = db.usernames.where(x => x.Id == user.Id).FirstOrDefault();
If the input is supposedly already validated, but suddenly can't be found this is an exception. Something really weird happened! But if your query is an attempt to validate it should be treated as a valid query with no results:
var user = db.usernames.Where(x => x.username == user.username).FirstOrDefault();
if (user == null)
{
// return useful error, this is not an exception
}

It depends, mostly you handle the common conditions that are likely to happen (such as database connection in your example) by using simple if statement. Other situations that might occur and you think your code won't cover all of them, use Exceptions, this way you ensure that you catch the error trace.
Some other cases might need both if and Exception.
example :
try
{
if(!string.IsNullOrEmpty(someString))
{
someClass.Run(someString);
}
}
catch(Exception ex)
{
// Log exception
}
as the example above (sorry couldn't think of a real-world case). We used try/catch to catch any unhandled errors, while in the same time, we already validating some known conditions in the try block.
So, it depends on which part you're dealing with in your code. But in all cases, you're supposed to try handling all other errors. You have always to keep avoiding exceptions in your code as much as possible.
You're the judge on your code, choose whatever you see fits best your code.
Here is A good reference for Best practices for exceptions

Related

When should I handle exceptions and when should they be thrown? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
When programming, I find myself having a hard time thinking about how my program should work, when an exception could be thrown.
Take the following example:
public void AddComponent(IEntityComponent component)
{
if (component == null)
{
// Should I throw an ArgumentNullException or should I just return?
}
if (ContainsComponentOfType(component.GetType()))
{
// Should I return here? Or should I throw an ArgumentException?
}
// Finally, we know we can add the component to the entity
components.Add(component);
}
public bool ContainsComponentOfType(Type componentType)
{
if (componentType == null)
{
// Should I throw an exception here? Should I return false?
}
return components.Any(c => c.GetType() == componentType);
}
Note that the above code will be used by people creating a game with my engine.
The policy can vary from zero tolerance (throwing exceptions at any point where they can be thrown) to lenient (where we forgive caller as far as we can do).
The common practice is DoAction (AddComponent in your case) be strict and TryDoAction (TryAddComponent) be lenient.
Zero tolerance version:
// Strict: we are quite sure in the arguments;
// that's why it's an exceptional case (error in the code!) if arguments are invalid
// and we fail to add
public void AddComponent(IEntityComponent component) {
// Contract: here we validate the input arguments
// Since we sure in them we apply zero tolerance policy:
// if contract is't met throw corresponding exception
// we want not null component
if (component == null)
throw new ArgumentException(nameof(component));
// which contains at least one item of the required type
if (ContainsComponentOfType(component.GetType()))
throw new ArgumentException("Component must contain...", nameof(component));
// Finally, we know we can add the component to the entity
components.Add(component);
}
Lenient implementation
// Lenient: we have arguments from the (unknown) source in which we are not sure
// we want just to try adding (and get true / false) if we succeed or not
public bool TryAddComponent(IEntityComponent component) {
// Contract: we validate the input arguments from unknown source
// if validation fails we should not throw any exception (it's not an
// exceptional case to get incorrect data from unreliable source) but
// let the caller know that we don't succeed
// We can't add if component is null
if (component == null)
return false;
// We have nothing to add if component doesn't contain required items
if (ContainsComponentOfType(component.GetType()))
return false;
// Finally, we know we can add the component to the entity
components.Add(component);
return true;
}
// Do we really want to expose it?
// ContainsComponentOfType is an implementation detail which we keep private
private bool ContainsComponentOfType(Type componentType) {
// Since it's a private method we can omit the check
return components.Any(c => c.GetType() == componentType);
}
Usage: since you are building an engine both cases (strict and lenient) can appear
MyClass loader = new MyClass();
...
// Cloud Database must not be corrupted; if it is, we want to know it immediatly
loader.AddComponent(componentFromCloud);
...
// Local file can contain any data: it can be corrupted, user can try cheating etc.
if (!loader.TryAddComponent(componentFromLocalFile)) {
// Let user know that saved data failed to be loaded
}
It depends on what you developing and how should it be used and who use it ...
In your case which is developing game engine the best practice is to throw exceptions and forward theme to end-user(developer who use your engine to develop the game) and let the developer handle the exceptions and do proper work that he/she want.
Always try to check all possible exceptions and give useful information about the exception and thew ways to fix the mistake that raise the exception. general exception handling is for unknown and unwanted exceptions that you don't know anything about theme.
It depends on what an error is to you and what an exception is, just because your code detects that something is not as it should and it can't continue you should throw an exception.
An exception, as its name implies, happens when something exceptional and not controlled or controllable by your code happens (i.e. network connection goes down, failed to save a file because other program has it locked, a null reference you have not controlled, etc.).
Throwing exceptions tends to be costly for a computer, as it has to include a stack of what has happened, where and information on the state of the call stack, just because of that, you want to avoid exceptions as much as possible.
As it is expected that your code might not be able to run from start to finish in a set of controled conditions you take into consideration, it is a good practice to control the flow and return values that indicate that the process has not run as it was expected to, but in this case, due to some expected error which you have controlled has happened and inform that error right away.
To sum up:
Avoid throwing exceptions for flow control of your methods, as they are costly and cause innecessary slowness on systems that consume your program.
Only throw the exceptions you have not covered in your code or that you can't control (i.e another program the user is running grabs a file you want to use and you did not consider this possibility).
Control as much error as you see necessary and inform the user with sensible information on what has happened in order for him to be able to solve it on his own (if he's capable to) so he can continue using and consuming your application.

What's the best practice to structure exception messages? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
When something goes wrong in your program, you can throw an exception in your code with a message that describes a problem. Typical example:
throw new Exception("Houston we have a problem");
Is it a good practice to pass a hardcoded string into an exception constructor? Maybe I should hold all of exception messages in a one place. Please tell me what's the best practice to solve a problem of exception message structuring.
As Tim mentioned in the comments already localization can be a problem if the messages are shown to users.
What my approach on this topic is, and what I really like to suggest is the following.
Try to make it generic.
Makea a constants class holding your exception Messages with meaningfull constants names like this:
public static const String IN_VARIABLE_MISSING = "An expected value is missing. Please try again";
This will give you the ability to actually re-use the exception wherever it is needed. ( Also you only need to edit it at one place and have it updated everywhere ) You can build a wrapper which will handle the localization. But there are so many options for that topic, that I will not elaborate too much.
So you then can throw an exception like this:
throw new Exception(IN_VARIABLE_MISSING);
If this is software which will be used commercial I would also recommend to write an own Exception which extends the standard Exception.
Why?
You can create an exception that will take your message and an number for example and will automatically build an unique key for you like this:
IN-MODULE-NUMBER-IDENTIFICATION
You see where that could be handy? Excactly in localization and in faster finding of where it happened and why it happened.
You can modify it to write IN at the beginning for Internal errors. VA for validation errors. Then the class/project where it happened and then a number or whatever you want.
This system will also give you the ability to use another string for that key depending on the locale the user is using.
TL;DR Make it reusable!
Is it a good practice to pass a hardcoded string into an exception constructor?
Yes and No.
No in the sense that this code:
throw new Exception("Houston we have a problem");
is much harder for the caller to deal with. That's because what the exception means is identified only by the text of the message; therefore a caller wanting to catch exceptions from your code (for example, so as not to crash but continue running if possible) has to make string comparisons to figure out what the problem was.
e.g.
try
{
someService.DoSomething(sessionId)
}
catch(Exception ex)
{
if (ex.Message.Contains("Houston"))
{
//this indicates that someService couldn't connect to the database
}
else if(ex.Message.Contains("is on fire"))
{
//someService detected that the network is exploded
}
else{
//we can only handle the two previous cases, all else is passed on}
throw;
}
As you can see this gets messy fast, and if someone changes the text....
Now this code, on the other hand:
throw new SomethingSpecificWentWrongException(sessionId);
where SomethingSpecificWentWrongException might look like this:
public class SomethingSpecificWentWrongException: Exception
{
public int SessionId {get;protected set;}
public SomethingSpecificWentWrongException(int sessionId):
base($"Something specific went horribly wrong with session {sessionId}")
{
SessionId=sessionId;
}
}
can easily be handled by the caller:
try
{
someService.DoSomething(sessionId)
}
catch(SomethingSpecificWentWrongException ex)
{
//do whatever it is you do to recover from this
}
catch(SomethingElseSpecificWentWrongException wex)
{
//recover from this
}
else
{
throw;
}
You'll notice that there is a hard-coded-ish string here but it's owned by the custom exception class itself, not by the code that decides to throw the exception; this makes a big difference because it means you can guarantee that wherever this exception is used the message is predictable (in terms of logging, etc).
So not only is it easier to reason about, it's a lot more maintainable than hard-coding strings provided by the throwing code.

C# - How to structure error handling in code properly [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I am fairly new to programming and I want to know what is the proper way to structure your error handling. I have searched the internet but I have failed to find something solid about the structure of ALL your try/catch/finally statements, and how they interact with each other.
I want to present my idea of how I think I should structure my error handling in code and I would like to invite everyone check if this is correct. A big bonus would be to back it up with some other research, a common practice of some sort.
So my way of doing this would be to put try statements pretty much everywhere! (I hope I haven't raged everyone by saying this). PS - I also understand about catching different types of exceptions, I am only catching of type 'Exception' just for explanation purposes.
So for example:
I start on Main in a normal console application and then I create an
instance of A.
I then call a member function on it called AMethod1 (a.AMethod1).
A.AMethod1 creates an instance of class B and then calls BMethod1
(b.BMethod1).
This is how I would go about error handling it:
public class Program
{
static void Main (string[] args)
{
//I do not place simple code like below inside the try statement,
//because it is unnecessary and will slow the process down.
//Is this correct?
const int importantNumber = 45;
string name;
IRepositoryFactory repoFactory;
A a;
//And then I put code in 'try' where I feel it may go wrong.
try
{
a = new A();
a.AMethod1();
//Some other code
}
catch (Exception ex)
{
HandleError(ex);
}
}
}
// End of scope of Program! The functions below belong to their relative
// classes.
public void AMethod1()
{
try
{
B b = new B();
b.BMethod1();
}
catch (Exception ex)
{
//Preserving the original exception and giving more detailed feedback.
//Is this correct?
//Alternative - you still could do a normal 'throw' like in BMethod1.
throw new Exception("Something failed", ex);
}
}
public void BMethod1()
{
try
{
//some code
}
catch (Exception ex)
{
throw; //So I don't lose stack trace - Is this correct?
}
}
In summary:
I put all code in try statements (except declarations like shown in
above code)
On the client level (at the start of the call stack) I
catch the error and handle it.
Going down the call stack, I just
throw the Exception so I don't break the stack information.
I would really appreciate some resources that explains how programmers are meant to structure their error handling. Please don't forget to read the comments within the code please.
Here are some good rules of thumb:
If you are going to log the error at the level in question, use exception handling
If there is some way to solve the exception, use exception handling
Otherwise, don't add any exception handling at that level
The exception to the rules above is the UI should ALWAYS (okay, maybe not always, but I can't think of an exception to this rule right off hand) have exception handling.
In general, if you are throwing the same error, as you have in your code, it is a sign you should not handle the exception. End of story.
NOTE: When I say "at that level", I mean in the individual class or method. Unless the exception handling is adding value, don't include it. It always adds value at the user interface level, as a user does not have to see your dirty laundry, a message saying "oops, laundry day" is enough.
In my personal experience most of the exceptions are related to null object reference. I tend to follow null object pattern to avoid lots of check for null values. And also while doing a value conversion I always use tryparse so that i dont stand a chance of null issues. all in all this subject could be discussed from many perspective. if you could be a bit more specific it will be easy to answer.
stackoverflow really isn't an opinion site. It's geared heavily towards specific answers to specific questions.
But you should know that try...catch does have some overhead associated with it. Putting it "everywhere" will hurt the performance of your code.
Just use it to wrap code that is subject to unexpected errors, such as writing to disk, for example.
Also note that the "correct" way depends on what you are doing with those errors. Are you logging them, reporting them to the user, propagating them to the caller? It just depends.

Why can't I write just a try with no catch or finally? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
Sometimes I do this and I've seen others doing it too:
VB:
Try
DontWannaCatchIt()
Catch
End Try
C#:
try
{
DontWannaCatchIt();
}
catch {}
I know I should catch every important exception that I'm expecting and do something about it, but sometimes it's not important to - or am I doing something wrong?
Is this usage of the try block incorrect, and the requirement of at least one catch or finally block an indication of it?
Update:
Now I understand the reason for this, and it's that I should at least comment on the empty catch block so others understand why it's empty. I should also catch only the exceptions I'm expecting.
Luckily for me I'm coding in VB so I can write it in just one catch:
Catch ex As Exception When TypeOf ex Is IOException _
OrElse TypeOf ex Is ArgumentException _
OrElse TypeOf ex Is NotSupportedException _
OrElse TypeOf ex Is SecurityException _
OrElse TypeOf ex Is UnauthorizedAccessException
'I don't actually care.
End Try
If you don't want to catch it, why are you using try in the first place?
A try statement means that you believe something can go wrong, and the catch says that you can adequately handle that which goes wrong.
So in your estimation:
try
{
//Something that can go wrong
}
catch
{
//An empty catch means I can handle whatever goes wrong. If a meteorite hits the
//datacenter, I can handle it.
}
That catch swallows any exceptions that happen. Are you that confident in your code that you can handle anything that goes wrong gracefully?
The best thing to do (for both yours and your maintenance programmer's sanity) is to explicitly state that which you can handle gracefully:
try
{
//Something that could throw MeteoriteHitDatacenterException
}
catch (MeteoriteHitDatacenterException ex)
{
//Please log when you're just catching something. Especially if the catch statement has side effects. Trust me.
ErrorLog.Log(ex, "Just logging so that I have something to check later on if this happens.")
}
No, you should not catch every important exception. It is okay to catch and ignore exceptions you don't care about, like an I/O error if there's nothing you can do to correct it and you don't want to bother reporting it to the user.
But you need to let exceptions like StackOverflowException and OutOfMemoryException propagate. Or, more commonly, NullReferenceException. These exceptions are typically errors that you did not anticipate, cannot recover from, should not recover from, and should not be suppressed.
If you want to ignore an exception then it is good to explicitly write an empty catch block in the code for that particular exception. This makes it clear exactly what exceptions you're ignoring. Ignoring exceptions very correctly is an opt-in procedure, not an opt-out one. Having an "ignore all exceptions" feature which can then be overridden to not ignore specific types would be a very bad language feature.
How do you know what types of exceptions are important and should not be caught? What if there are exceptions you don't know about? How do you know you won't end up suppressing important errors you're not familiar with?
try
{
}
// I don't care about exceptions.
catch
{
}
// Okay, well, except for system errors like out of memory or stack overflow.
// I need to let those propagate.
catch (SystemException exception)
{
// Unless this is an I/O exception, which I don't care about.
if (exception is IOException)
{
// Ignore.
}
else
{
throw;
}
}
// Or lock recursion exceptions, whatever those are... Probably shouldn't hide those.
catch (LockRecursionException exception)
{
throw;
}
// Or, uh, what else? What am I missing?
catch (???)
{
}
No catch or finally is invalid. Empty catch or finally is valid. Empty catch means you don't care about exceptions, you just try to do something and it doesn't matter if it doesn't work, you just want to go on. Useful in cleanup functions for example.
Also if you haven't to do something about an error maybe you should specify what kind of exception the program has to ignore.
If you have to ignore every exception, I can't see why you can't use try/catch in this way.
It's usually a mistake. Exceptions signal, well, exceptional behavior; when an exception is thrown it should mean that something went wrong. So to continue normal program flow as if nothing went wrong is a way of hiding an error, a form of denial. Instead, think about how your code should handle the exceptional case, and write code to make that happen. An error that propagates because you've covered it up is much harder to debug than one that surfaces immediately.
It's not made easy for you to do because it's considered bad practice by the majority of developers.
What if someone later adds a method call to the body of DontWannaCatchIt() that does throw an exception worth catching, but it gets swallowed by your empty catch block? What if there are some exceptions that you actually would want to catch, but didn't realize it at the time?
If you absolutely must do this, try to be as specific as possible with the type of exception you're going to catch. If not, perhaps logging the exception is an option.
An error exists, has been thrown, and needs to go somewhere. Normal code flow has been aborted and the fan needs cleaned.
No catch block = indeterminate state. Where should the code go? What should it do?
An empty catch block = error handled by ignoring it.
Note: VBA has a vile "On Error Continue"...
The reason I've heard is that if your try fails for ANY reason, giving you control of the error response is highly preferable to giving the Framework control of it, i.e., yellow screen or error 500.
what if you write only code with try
try
{
int j =0;
5/j;
}
this would equivalent to write
int j =0;
5/j;
so writing try does not make any sense , it only increse your count of lines.
now if you write try with empty catch or finally , you are explicitley instructing runtime to behave differently.
so that' why i think empty try block is not possible.
Yes, it is incorrect. It's like goto: one per 100 KLoc is fine, but if you need many of these, you are doing it wrong.
Swallowing exceptions without any reactions is one of the worse things in error handling, and it should at least be explicit:
try
{
DontWannaCatchIt();
}
catch
{
// This exception is ignored based on Spec Ref. 7.2.a,
// the user gets a failure report from the actual results,
// and diagnostic details are available in the event log (as for every exception)
}
The further-away-look:
Error handling is an aspect: in some contexts, an error needs to be thrown and propagate up the call stack (e.g. you copy a file, copy fails).
Calling the same code in a different context might require the error to be tracked, but the operation to continue (e.g. Copying 100 files, with a log indicating which files failed).
Even in this case, an empty catch handler is wrong.
With most languages, there is no other direct implementation than to try+catch within the loop, and build the log in the catch handler. (You could build a mroe flexible mechanism, though: Have a per-call-thread handler that can either throw, or stow away the message. However, interaction with debugging tools suffers without direct language support.)
A sensible use case would be implementing a TryX() from a X(), but that would have to return the exception in question.

Is it ok to catch all exception types if you rethrow them wrapped another exception?

I know you're not suppose to write code that caches all exception types like this.
try
{
//code that can throw an exception
}
catch
{
//what? I don't see no
}
Instead you're suppose to do something more like the code below allowing any other exception that you didn't expect to bubble up.
try
{
//code that can throw an exception
}
catch(TypeAException)
{
//TypeA specific code
}
catch(TypeBException)
{
//TypeB specific code
}
But is it ok to catch all exception types if you are wrapping them with another exception?
Consider this Save() method below I am writing as part of a Catalog class. Is there anything wrong with me catching all exception types and returning a single custom CatalogIOException with the original exception as the inner exception?
Basically I don't want any calling code to have to know anything about all the specific exceptions that could be thrown inside of the Save() method. They only need to know if they tried to save a read only catalog (CatalogReadOnlyException), the catalog could not be serialized (CatalogSerializationException), or if there was some problem writing to the file (CatalogIOException).
Is this a good or bad way to handle exceptions?
/// <summary>
/// Saves the catalog
/// </summary>
/// <exception cref="CatalogReadOnlyException"></exception>
/// <exception cref="CatalogIOException"></exception>
/// <exception cref="CatalogSerializingExeption"></exception>
public void Save()
{
if (!this.ReadOnly)
{
try
{
System.Xml.Serialization.XmlSerializer serializer = new XmlSerializer(typeof(Catalog));
this._catfileStream.SetLength(0); //clears the file stream
serializer.Serialize(this._catfileStream, this);
}
catch (InvalidOperationException exp)
{
throw new CatalogSerializationException("There was a problem serializing the catalog", exp);
}
catch (Exception exp)
{
throw new CatalogIOException("There was a problem accessing the catalog file", exp);
}
}
else
{
throw new CatalogReadOnlyException();
}
}
Update 1
Thanks for all the responses so far. It sounds like the consensus is I shouldn't be doing this, and I should only be catching exceptions if I actually have something to do with them. In the case of this Save() method there really isn't any exception that may be thrown that I want to handle in the Save() method itself. Mostly I just want to notify the user why they were not able to save.
I think my real problem is I'm using exceptions as a way to notify the user of problems, and I'm letting this inform how I am creating and handling exceptions a little too much. So instead should it sounds like it would be better to not catch any exceptions and let the UI layer figure out how to notify the user, and or crash. Is this correct? Consider the Save Menu event handler below.
private void saveCatalogToolStripMenuItem_Click(object sender, EventArgs e)
{
//Check if the catalog is read only
if (this.Catalog.ReadOnly)
{
MessageBox.Show("The currently opened catalog is readonly and can not be saved");
return;
}
//attempts to save
try
{
//Save method doesn't catch anything it can't deal with directly
this.Catalog.Save();
}
catch (System.IO.FileNotFoundException)
{
MessageBox.Show("The catalog file could not be found");
}
catch (InvalidOperationException exp)
{
MessageBox.Show("There was a problem serializing the catalog for saving: " + exp.Message);
}
catch (System.IO.IOException exp)
{
MessageBox.Show("There was a problem accessing the catalog file: " + exp.Message);
}
catch (Exception exp)
{
MessageBox.Show("There was a problem saving the catalog:" + exp.Message);
}
}
Update 2
One more thing. Would the answer change at all if the Save() method was part of a public API vs internal code? For example if it was part of a public API then I'd have to figure out and document all the possible exceptions that Save() may throw. This would be a lot easier if knew that Save() could only possibly throw one of my three custom exceptions.
Also if Save() was part of a public API wouldn't security also be a concern? Maybe I would want to let the consumer of the API know that the save wasn't successful, but I don't want expose anything about how Save() works by letting them get at the exceptions that may have been generated.
Doing a generic catch-all and rethrowing as a new type of exception does not really solve your problem and does not give you anything.
What you really need to do is to catch the exceptions that you can handle and then handle them (at the appropriate level - this is where rethrowing may be useful). All other exceptions either need to be logged so you can debug why they happened, or shouldn't be happening in the first place (for example - make sure you validate user input, etc.). If you catch all exceptions, you'll never really know why you're getting the exceptions you're getting and, thus, cannot fix them.
Updated Response
In response to the update of your question (particularly in how you want to handle the save case), my question to you would be - why are you using exceptions as a means of determine the path your program takes? For example, let's take the "FileNotFoundException." Obviously that can happen at times. But, instead of letting a problem happen and notifying the user about it, before saving (or doing whatever) with the file, why not check first that the file can be found. You still get the same effect, but you aren't using exceptions to control program flow.
I hope this all makes sense. Let me know if you have any additional questions.
When you re-throw with the original exception as inner exception, you lose the original stack trace, which is valuable debugging information.
I will sometimes do what you are suggesting, but I always log the original exception first to preserve the stack trace.
I don't see a problem with what you are doing. The reason for wrapping exceptions in a custom exception types is to create an abstraction between layers of code -- to translate lower-level errors into a higher-level context. Doing this relieves the calling code from having to know too much the implementation details of what Save does.
Your update #1 is an example of the calling code having to know way too much about the implementation details of Save(). In response to your second update, I agree 100%
PS
I'm not saying to do this in every scenario where you encounter exceptions. Only when the benefit outweighs the cost (usually at module boundaries).
Example scenarios for when this is especially useful: you are wrapping a 3rd party library, you don't yet know all the underlying exceptions that might be thrown, you don't have the source code or any documentation, and so on.
Also, he is wrapping the underlying exception and no information is lost. The exception can still be logged appropriately (though you'll need to recursion your way through the InnerExceptions).
I favor wrapping exceptions, from the standpoint that a custom exception hierarchy can divide exceptions into much more useful classifications than the default hierarchy. Suppose one tries to open a document and gets an ArgumentException or an InvalidOperationException. Does the type of the exception really contain any useful information whatsoever? Suppose, however, one instead got a CodecNotFoundException, a PrerenderFingFailureException, or a FontLoadFailureException. One can imagine the system catching some of those exceptions and attempting to do something about it (e.g. allow the user to search for a CODEC, retry rendering with lower-resolution settings, or allow substitution of fonts after warning the user). Much more useful than the default exceptions, many of which say nothing about what's really wrong or what can be done about it.
From a hierarchical standpoint, what's really needed is a means of distinguishing exceptions which indicate that the method throwing the exception was unable to perform its task, but the system state is similar to what it was before the method was started, and those which indicate that the system state is corrupt in a fashion beyond that implied by the method's failure. The normal exception hierarchy is completely useless for that; if one wraps exceptions one may be able to improve the situation slightly (though not as well as if the hierarchy were better designed to start with). An exception which forces a transaction to be unwound is not nearly as bad as one which occurs while committing or unwinding a transaction. In the former case, the state of the system is known; in the latter case, it isn't.
While one should probably avoid catching certain really bad exceptions (StackOverflowException, OutOfMemoryException, ThreadAbortException) I'm not sure it really matters. If the system is going to crash and burn, it's going to do so whether one catches the exception or not. In vb.net, it may be worthwhile to "Catch Ex As Exception When IsNotHorribleException(Ex)" but C# has no such construct, nor even a way to exclude certain exceptions from being caught.
Parting note: in some cases, one operation may generate multiple exceptions that are worthy of logging. Only by wrapping exceptions in a custom exception which holds a list of other exceptions can that really be accomplished.
I don't think its a good idea.
You should only add you own type of exception, if you have anything to add.
And furthermore, you should only catch exceptions that you expect, and that you are able to handle - all other exceptions should be allowed to bubble up.
As a developer I must say, I get angry if you try to "hide" exceptions from me, by swallowing or wrapping them.
For some more info on why catch(exception) is bad check out this article: http://blogs.msdn.com/clrteam/archive/2009/02/19/why-catch-exception-empty-catch-is-bad.aspx
Essentially catching 'Exception' is like saying 'if anything goes wrong I dont care carry on' and catching 'Exception' and wrapping it is like saying 'if anything goes wrong treat them as if they all went wrong for the exact same reason'.
This cannot be correct either you handle it because you semi-expected it or you totally don't think it should ever happen EVER (or didn't know it would). In this case you'd want some kind of app level logging to point you to an issue that you had never expected - not just a one size fits all solution.
My own rule of thumb is to catch and wrap Exception only if I have some useful context I can add, like the file name I was trying to access, or the connection string, etc. If an InvalidOperationException pops up in your UI with no other information attached, you're going to have a hell of a time tracking down the bug.
I catch specific exception types only if the context or message I want to add can be made more useful for that exception compared to what I would say for Exception generally.
Otherwise, I let the exception bubble up to another method that might have something useful to add. What I don't want to do is tie myself in knots trying to catch and declare and handle every possible exception type, especially since you never know when the runtime might throw a sneaky ThreadAbortException or OutOfMemoryException.
So, in your example, I would do something like this:
try
{
System.Xml.Serialization.XmlSerializer serializer =
new XmlSerializer(typeof(Catalog));
this._catfileStream.SetLength(0); //clears the file stream
serializer.Serialize(this._catfileStream, this);
}
// catch (InvalidOperationException exp)
// Don't catch this because I have nothing specific to add that
// I wouldn't also say for all exceptions.
catch (Exception exp)
{
throw new CatalogIOException(
string.Format("There was a problem accessing catalog file '{0}'. ({1})",
_catfileStream.Name, exp.Message), exp);
}
Consider adding the inner exception's message to your wrapper exception so that if a user just sends you a screenshot of the error dialog, you at least have all the messages, not just the top one; and if you can, write the whole ex.ToString() to a log file somewhere.
In this particular case exceptions should be rare enough that wrapping it shouldn't be a useful thing and will likely just get in the way of error handling down the line. There are plenty of examples within the .Net framework where a specific exception that I can handle is wrapped in a more general one and it makes it much more difficult (though not impossible) for me to handle the specific case.
I have written an article on this very topic before. In it I reiterate the importance of capturing as much data about the exception as is possible. Here's the URL to the article:
http://it.toolbox.com/blogs/paytonbyrd/improve-exception-handling-with-reflection-and-generics-8718
What benefit does the user get from being told "There was a problem serializing the catalog"? I suppose your problem domain might be an extraordinary case, but every group of users I've ever programmed for would respond the same way when reading that message: "The program blew up. Something about the catalog."
I don't mean to be condescending towards my users; I'm not. It's just that generally speaking my users have better things to do with their attention than squander it constructing a fine-grained mental model of what's going on inside my software. There have been times when my users have had to build that kind of an understanding in order to use a program I've written, and I can tell you that the experience was not salutary for them or for me.
I think your time would be much better spent on figuring out how to reliably log exceptions and relevant application state in a form that you can access when your users tell you that something broke than in coming up with an elaborate structure for producing error messages that people are unlikely to understand.
To answer this question, you need to understand why catching System.Exception is a bad idea, and understand your own motivations for doing what your propose.
It's a bad idea because it makes the statement that anything that could have gone wrong is okay, and that the application is in a good state to keep running afterwards. That's a very bold statement to make.
So the question is: Is what you are proposing equivalent to catching System.Exception? Does it give the consumer of your API any more knowledge to make a better judgement? Does it simply encourage them to catch YourWrappedException, which is then the moral equivalent of catching System.Exception, except for not triggering FXCop warnings?
In most cases, if you know there's a rule against doing something, and want to know if something similar is "okay", you should start with understanding the rationale for the original rule.
This is a standard practice in .NET and how exceptions should be handled, especially for exceptions that are recoverable from.
Edit: I really have no idea why I'm being downvoted perhaps I read more into the authors intent than everyone else. But the way I read the code the fact he is wrapping those exceptions into his custom exception implies that the consumer of this method is equiped to handle those exceptions and that it is a responsibility of the consumer to deal with the error processing.
Not a single person that DV'd actually left any form of actual dispute. I stand by my answer that this is perfectly acceptable because the consumer should be aware of the potential exceptions this could throw and be equipped to handle them which is shown by the explicit wrapping of the exception. This also preserves the original exception so the stack trace is available and underlying exception accessible.

Categories

Resources