Fires of Heaven Guild Message Board  

Go Back   Fires of Heaven Guild Message Board > General forums > Development
User Name
Password
Or, use your gamerDNA username: (more...)
ForumSpy Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply
 
LinkBack Thread Tools Search this Thread Rate Thread Display Modes
Old 06-24-2008, 04:24 PM   #1 (permalink)
PigBenis
duh
 
PigBenis's Avatar
 
Join Date: May 2002
Location: Boiler Up
Posts: 636
-34 Internets
Send a message via AIM to PigBenis
Exception handling

Hey guys can anyone point me in the direction of a good resource to learn some proper methods for exception handling. Specifically for OO C# type stuff. I've been programming for a while now, but I've never really got a good grasp on exception handling. Thanks infoz~
PigBenis is offline   Reply With Quote
Old 06-24-2008, 06:29 PM   #2 (permalink)
Tripamang
Registered User
 
Join Date: Jul 2002
Posts: 2,026
-7 Internets
I find it pretty simple, I hope my example helps. There really aren't that many great resources dedicated to this stuff because it is such a simple concept when it comes down to it.

try {


}
catch (Exception e) {

}
catch (...) {

}

Exception is the default exception class in C#, almost any built in functionality will throw this type of exception. I suggest just playing around with the class and it's contents to get a feel of what kind of stuff it can contain.

You typically want to put your try catches around the things you want to halt if there is a problem or to handle an error. An Example would be like:

try {
DeleteAllDirectories();
}
catch ( Exception e) {
WriteError(e.Error);
return false;
}

CreateAllDirectories();

So lets say this is some stupid app that deletes all the directories in a folder, and then recreates them all. You don't want to try creating the directories if you couldn't delete them all because that would lead to further issue. So you put the try/catch around the DeleteAllDirectories function to catch the error that happens so the user knows why, as well as preventing the program from attempting to create the directories.

Then you have the throw functionality...

You can throw any object your heart desires and it will immediately stop what it's doing and the catch has to grab that object. The catches have to match the object you're throwing. An Example...

try {
Pants();
}
catch (string sError) {
WriteError(sError);
}

void Pants () {
if (!bPants)
throw "There are no pants!";
}

In the above example I've created a try catch that catches a string, I'm throwing a string so that catch will grab it and perform the action I requested. If I threw an exception class since it's unhandled by a catch it would crash the app, which is why you always have to catch your exceptions :P

catch(...) will blanketly catch any exception, there good if you just don't want something to crash if it fails Any object caught is essentially destroyed, so you lack any information as to why the exception happened.


In C++ we commonly wrap try/catches on top of eachother at the various levels of the app, so if we're 3-4 calls deep each layer throws an exception with it's information and we keep adding to the exception object till we reach the top layer. This full exception is a god send for debugging on client machines as we have the line numbers/stack trace of what happened.

Dunno hope this helps a bit :P
__________________
Black Atom - Crescent of the Red Moon - Red Moon Federation

Tripamang is offline   Reply With Quote
Old 06-24-2008, 08:01 PM   #3 (permalink)
PigBenis
duh
 
PigBenis's Avatar
 
Join Date: May 2002
Location: Boiler Up
Posts: 636
-34 Internets
Send a message via AIM to PigBenis
Thanks man that helps a bunch. Here's an example of something that kind of confused.

I have 3 methods 1 method calls 2nd method and 2nd method calls a helper 3rd method. If the exception happens in the 3rd helper method you can wrap a try catch around it and it will be caught, however the code will return to the 2nd method and continue. If I put no try catch around the 3rd the 2nd will catch it and code will continue at the first. Now if I only have try catch around 1st and exception happens on 3rd it wont be caught at the first

lol I really hope this wasn't too confusing. I mean if I'm 3 calls deep how can I have ALL execution terminate without having to set some kind of error flag and check that flag?
PigBenis is offline   Reply With Quote
Old 06-24-2008, 08:04 PM   #4 (permalink)
Tripamang
Registered User
 
Join Date: Jul 2002
Posts: 2,026
-7 Internets
Quote:
Originally Posted by PigBenis View Post
Thanks man that helps a bunch. Here's an example of something that kind of confused.

I have 3 methods 1 method calls 2nd method and 2nd method calls a helper 3rd method. If the exception happens in the 3rd helper method you can wrap a try catch around it and it will be caught, however the code will return to the 2nd method and continue. If I put no try catch around the 3rd the 2nd will catch it and code will continue at the first. Now if I only have try catch around 1st and exception happens on 3rd it wont be caught at the first

lol I really hope this wasn't too confusing. I mean if I'm 3 calls deep how can I have ALL execution terminate without having to set some kind of error flag and check that flag?
In the exception at the lowest level throw again.

try
{

stuff that throws exception

}
catch (object thrown) {
Add error to object
throw object; <-- throw it a second time, it gets caught in the level above it repeat till you get the level you want to stop at.
}


That's pretty much what microsoft does with the exception class, so you can see every level/method that the error was involved with like a stack trace to your error. I found this stuff really confusing at first, most places are just like "omg it throw object you catch like baseball" and that's a half page analogy on how it works. Once I started playing with it the power of it became pretty evident and the simplicity awesome
__________________
Black Atom - Crescent of the Red Moon - Red Moon Federation


Last edited by Tripamang : 06-24-2008 at 08:07 PM.
Tripamang is offline   Reply With Quote
Old 06-25-2008, 04:15 PM   #5 (permalink)
PigBenis
duh
 
PigBenis's Avatar
 
Join Date: May 2002
Location: Boiler Up
Posts: 636
-34 Internets
Send a message via AIM to PigBenis
ohh ok I see, I'll try that out thanks man.
PigBenis is offline   Reply With Quote
Old 06-25-2008, 04:46 PM   #6 (permalink)
Zippygoose
Math Enthusiast/Badass MC
 
Zippygoose's Avatar
 
Join Date: Jun 2002
Location: Seattle
Posts: 650
+0 Internets
Send a message via AIM to Zippygoose
Another best practice is to catch specific exceptions before general exceptions. Code Analysis tools like FxCop will complain about catching only generic exceptions. For example, if you were working with an Xml document, you should catch Xml-specific exceptions first:

try
{
Do Xml-specific stuff
}
catch(XmlException xe)
{
Display Xml-specific error message
}
catch(Exception e)
{
Display unexpected error
}

Kind of nitpicky but that's how MS likes it. Also, try/catches are pretty resource intensive.
Zippygoose is online now   Reply With Quote
Old 06-26-2008, 10:31 AM   #7 (permalink)
x1hundredregrets
Reactor Zero
 
x1hundredregrets's Avatar
 
Join Date: Dec 2002
Posts: 319
-5 Internets
The above posters have covered the basics pretty well, so follow what they say. In regards to WHEN you should use exceptions vs. return codes: Here is an excerpt from the C++ FAQ Lite (it applies to C# too) that offers a really good explanation of the way exceptions should be used in a professional setting:

Quote:
[17.12] Exception handling seems to make my life more difficult; clearly I'm not the problem, am I??

Absolutely you might be the problem!

The C++ exception handling mechanism can be powerful and useful, but if you use it with the wrong mindset, the result can be a mess. If you're getting bad results, for instance, if your code seems unnecessarily convoluted or overly cluttered with try blocks, you might be suffering from a "wrong mindset." This FAQ gives you a list of some of those wrong mindsets.

Warning: do not be simplistic about these "wrong mindsets." They are guidelines and ways of thinking, not hard and fast rules. Sometimes you will do the exact opposite of what they recommend — do not write me about some situation that is an exception (no pun intended) to one or more of them — I guarantee that there are exceptions. That's not the point.

Here are some "wrong exception-handling mindsets" in no apparent order:

* The return-codes mindset: This causes programmers to clutter their code with gobs of try blocks. Basically they think of a throw as a glorified return code, and a try/catch as a glorified "if the return code indicates an error" test, and they put one of these try blocks around just about every function that can throw.

* The Java mindset: In Java, non-memory resources are reclaimed via explicit try/finally blocks. When this mindset is used in C++, it results in a large number of unnecessary try blocks, which, compared with RAII, clutters the code and makes the logic harder to follow. Essentially the code swaps back and forth between the "good path" and the "bad path" (the latter meaning the path taken during an exception). With RAII, the code is mostly optimistic — it's all the "good path," and the cleanup code is buried in destructors of the resource-owning objects. This also helps reduce the cost of code reviews and unit-testing, since these "resource-owning objects" can be validated in isolation (with explicit try/catch blocks, each copy must be unit-tested and inspected individually; they cannot be handled as a group).

* Organizing the exception classes around the physical thrower rather than the logical reason for the throw: For example, in a banking app, suppose any of five subsystems might throw an exception when the customer has insufficient funds. The right approach is to throw an exception representing the reason for the throw, e.g., an "insufficient funds exception"; the wrong mindset is for each subsystem to throw a subsystem-specific exception. For example, the Foo subsystem might throw objects of class FooException, the Bar subsystem might throw objects of class BarException, etc. This often leads to extra try/catch blocks, e.g., to catch a FooException, repackage it into a BarException, then throw the latter. In general, exception classes should represent the problem, not the chunk of code that noticed the problem.

* Using the bits / data within an exception object to differentiate different categories of errors: Suppose the Foo subsystem in our banking app throws exceptions for bad account numbers, for attempting to liquidate an illiquid asset, and for insufficient funds. When these three logically distinct kinds of errors are represented by the same exception class, the catchers need to say if to figure out what the problem really was. If your code wants to handle only bad account numbers, you need to catch the master exception class, then use if to determine whether it is one you really want to handle, and if not, to rethrow it. In general, the preferred approach is for the error condition's logical category to get encoded into the type of the exception object, not into the data of the exception object.

* Designing exception classes on a subsystem by subsystem basis: In the bad old days, the specific meaning of any given return-code was local to a given function or API. Just because one function uses the return-code of 3 to mean "success," it was still perfectly acceptable for another function to use 3 to mean something entirely different, e.g., "failed due to out of memory." Consistency has always been preferred, but often that didn't happen because it didn't need to happen. People coming with that mentality often treat C++ exception-handling the same way: they assume exception classes can be localized to a subsystem. That causes no end of grief, e.g., lots of extra try blocks to catch then throw a repackaged variant of the same exception. In large systems, exception hierarchies must be designed with a system-wide mindset. Exception classes cross subsystem boundaries — they are part of the intellectual glue that holds the architecture together.

* Use of raw (as opposed to smart) pointers: This is actually just a special case of non-RAII coding, but I'm calling it out because it is so common. The result of using raw pointers is, as above, lots of extra try/catch blocks whose only purpose in life is to delete an object then re-throw the exception.

* Confusing logical errors with runtime situations: For example, suppose you have a function f(Foo* p) that must never be called with the NULL pointer. However you discover that somebody somewhere is sometimes passing a NULL pointer anyway. There are two possibilities: either they are passing NULL because they got bad data from an external user (for example, the user forgot to fill in a field and that ultimately resulted in a NULL pointer) or they just plain made a mistake in their own code. In the former case, you should throw an exception since it is a runtime situation (i.e., something you can't detect by a careful code-review; it is not a bug). In the latter case, you should definitely fix the bug in the caller's code. You can still add some code to write a message in the log-file if it ever happens again, and you can even throw an exception if it ever happens again, but you must not merely change the code within f(Foo* p); you must, must, MUST fix the code in the
caller(s) of f(Foo* p).

There are other "wrong exception-handling mindsets," but hopefully those will help you out. And remember: don't take those as hard and fast rules. They are guidelines, and there are exceptions to each.
x1hundredregrets is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is On
Trackbacks are On
Pingbacks are On
Refbacks are On
uberguilds network



All times are GMT -7. The time now is 01:28 AM.


Powered by vBulletin® Version 3.6.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.0.0 RC6