How to Implement One "Catch'Em All" Exception Handler with Resume

.NET - What's the best way to implement a catch all exceptions handler

I have just played with AppDomain's UnhandledException behavior,
(this is the last stage the unhandled exception is registered at)

Yes, after processing the event handlers your application will be terminated and the nasty "... program stopped working dialog" shown.

:)
You still can avoid that.

Check out:

class Program
{
void Run()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

Console.WriteLine("Press enter to exit.");

do
{
(new Thread(delegate()
{
throw new ArgumentException("ha-ha");
})).Start();

} while (Console.ReadLine().Trim().ToLowerInvariant() == "x");

Console.WriteLine("last good-bye");
}

int r = 0;

void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Interlocked.Increment(ref r);
Console.WriteLine("handled. {0}", r);
Console.WriteLine("Terminating " + e.IsTerminating.ToString());

Thread.CurrentThread.IsBackground = true;
Thread.CurrentThread.Name = "Dead thread";

while (true)
Thread.Sleep(TimeSpan.FromHours(1));
//Process.GetCurrentProcess().Kill();
}

static void Main(string[] args)
{
Console.WriteLine("...");
(new Program()).Run();
}
}

P.S. Do handle the unhandled for Application.ThreadException (WinForms) or DispatcherUnhandledException (WPF) at the higher level.

Is it really that bad to catch a general exception?

Obviously this is one of those questions where the only real answer is "it depends."

The main thing it depends on is where your are catching the exception. In general libraries should be more conservative with catching exceptions whereas at the top level of your program (e.g. in your main method or in the top of the action method in a controller, etc) you can be more liberal with what you catch.

The reason for this is that e.g. you don't want to catch all exceptions in a library because you may mask problems that have nothing to do with your library, like "OutOfMemoryException" which you really would prefer bubbles up so that the user can be notified, etc. On the other hand, if you are talking about catching exceptions inside your main() method which catches the exception, displays it and then exits... well, it's probably safe to catch just about any exception here.

The most important rule about catching all exceptions is that you should never just swallow all exceptions silently... e.g. something like this in Java:

try { 
something();
} catch (Exception ex) {}

or this in Python:

try:
something()
except:
pass

Because these can be some of the hardest issues to track down.

A good rule of thumb is that you should only catch exceptions that you can properly deal with yourself. If you cannot handle the exception completely then you should let it bubble up to someone who can.

How to resume computation on exception in C#?

Using separate try .. catch constructs would be the best thing to do in general, because you should handle the most specific exceptions (which can be different for different statements). Also, an exception can create an invalid state, so continuing may not be the best thing to do.

If you're just looking for a simpler syntax to write it and you need to repeat the same exception handling, you can use lambdas and write something like:

CallWithCatch
( () => statement1,
() => statement2,
() => statement3,
/* ... */ );

Where the definition of CallWithCatch looks like this:

void CallWithCatch(params Action[] statements) {
foreach(var statement in statements) {
try {
statement();
} catch(/* your exception */) {
// your exception handler
}
}
}

How using try catch for exception handling is best practice

My exception-handling strategy is:

  • To catch all unhandled exceptions by hooking to the Application.ThreadException event, then decide:

    • For a UI application: to pop it to the user with an apology message (WinForms)
    • For a Service or a Console application: log it to a file (service or console)

Then I always enclose every piece of code that is run externally in try/catch :

  • All events fired by the WinForms infrastructure (Load, Click, SelectedChanged...)
  • All events fired by third party components

Then I enclose in 'try/catch'

  • All the operations that I know might not work all the time (IO operations, calculations with a potential zero division...). In such a case, I throw a new ApplicationException("custom message", innerException) to keep track of what really happened

Additionally, I try my best to sort exceptions correctly. There are exceptions which:

  • need to be shown to the user immediately

  • require some extra processing to put things together when they happen to avoid cascading problems (ie: put .EndUpdate in the finally section during a TreeView fill)

  • the user does not care, but it is important to know what happened. So I always log them:

  • In the event log

  • or in a .log file on the disk

It is a good practice to design some static methods to handle exceptions in the application top level error handlers.

I also force myself to try to:

  • Remember ALL exceptions are bubbled up to the top level. It is not necessary to put exception handlers everywhere.
  • Reusable or deep called functions does not need to display or log exceptions : they are either bubbled up automatically or rethrown with some custom messages in my exception handlers.

So finally:

Bad:

// DON'T DO THIS; ITS BAD
try
{
...
}
catch
{
// only air...
}

Useless:

// DON'T DO THIS; IT'S USELESS
try
{
...
}
catch(Exception ex)
{
throw ex;
}

Having a try finally without a catch is perfectly valid:

try
{
listView1.BeginUpdate();

// If an exception occurs in the following code, then the finally will be executed
// and the exception will be thrown
...
}
finally
{
// I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURRED OR NOT
listView1.EndUpdate();
}

What I do at the top level:

// i.e When the user clicks on a button
try
{
...
}
catch(Exception ex)
{
ex.Log(); // Log exception

-- OR --

ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

What I do in some called functions:

// Calculation module
try
{
...
}
catch(Exception ex)
{
// Add useful information to the exception
throw new ApplicationException("Something wrong happened in the calculation module:", ex);
}

// IO module
try
{
...
}
catch(Exception ex)
{
throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

There is a lot to do with exception handling (Custom Exceptions) but those rules that I try to keep in mind are enough for the simple applications I do.

Here is an example of extensions methods to handle caught exceptions a comfortable way. They are implemented in a way they can be chained together, and it is very easy to add your own caught exception processing.

// Usage:

try
{
// boom
}
catch(Exception ex)
{
// Only log exception
ex.Log();

-- OR --

// Only display exception
ex.Display();

-- OR --

// Log, then display exception
ex.Log().Display();

-- OR --

// Add some user-friendly message to an exception
new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
return ex;
}

How to resume code even after exception handling with try and catch in java

Here's a more elegant solution to this problem. No try-catch involved.

import java.io.*;
import java.lang;
public class
{
//Compares response to the string representations of all numbers between 1 and numOptions, inclusive.
//Returns the matching integer or -1 otherwise.
public static int parseResponse(String response, int numOptions)
{
for(int i=1;i<=numOptions;i++) {
if(response.equals(Integer.toString(i))) return i;
}
return -1;
}

public static void main()throws IOException
{
InputStreamReader read =new InputStreamReader (System.in);
BufferedReader in =new BufferedReader (read);
System.out.println(" Select your category");
System.out.println(" 1. Food");
System.out.println(" 2. National");
System.out.println("");
System.out.println(" Enter your choice");

//New code
int choice=-1;
while(choice==-1) {
choice=parseResponse(in.readLine(),2);
if(choice==-1)
{
System.out.println(" Invalid input. Please enter a number between 1-2");
}
}

if(choice==1)//food category
{
int score = 0;
System.out.println("what are dynamites made?");
System.out.println("1. peanuts");System.out.println("2. grapes");
System.out.println("3. flaxseeds");System.out.println("4. fish");
System.out.println(" Enter your choice");

//New code
int food1=-1;
while(food1==-1) {
food1=parseResponse(in.readLine(),4);
if(food1==-1)
{
System.out.println(" Invalid input. Please enter a number between 1-4");
}
}

if(food1==1)
{ System.out.println(" Correct answer");
score=score+10
}
else
{
System.out.println(" Wronge answer");
score=score+0
}
//then i have the second question with the same format
}
if(choice==2)//natioanl category with the same format as above
{//two question with if else statements in them
}
}
}// also help me where to add the try and catch statements

In case you don't know:

 if(response.equals(Integer.toString(i))) return i;

is the same as

 if(response.equals(Integer.toString(i)))
{
return i;
}

Exception handling in entire application

0) Avoid exceptions in Cocoa. They are generally non-recoverable. You might catch them for your own error reporting, but it's generally unsafe to assume you can recover from them.

1) If you need to catch, catch it immediately. Don't write your own throws -- instead, convert it to something like an NSError and pass that around. NSError can contain all the information you need to display or send an error code as well as a localized message.

2) You cannot convert an NSException into an NSError (directly) because an NSException does not have all the properties an NSError has - it is a different data representation. For one, an error code is not available. Two, the description is not localized. The best you can do is to create an error code and domain, then use the properties you need from the NSException and store that in an NSError. This could look something like the following:

// error checking omitted
extern NSString* const MONExceptionHandlerDomain;
extern const int MONNSExceptionEncounteredErrorCode;

NSError * NewNSErrorFromException(NSException * exc) {
NSMutableDictionary * info = [NSMutableDictionary dictionary];
[info setValue:exc.name forKey:@"MONExceptionName"];
[info setValue:exc.reason forKey:@"MONExceptionReason"];
[info setValue:exc.callStackReturnAddresses forKey:@"MONExceptionCallStackReturnAddresses"];
[info setValue:exc.callStackSymbols forKey:@"MONExceptionCallStackSymbols"];
[info setValue:exc.userInfo forKey:@"MONExceptionUserInfo"];

return [[NSError alloc] initWithDomain:MONExceptionHandlerDomain code:MONNSExceptionEncounteredErrorCode userInfo:info];
}

@catch (NSException * exc) {
NSError * err = NewNSErrorFromException(exc);
...
}

If the APIs you use throw exceptions you are expected to catch and recover from (e.g. not truly exceptional cases), then yes, you could catch and attempt to continue. Unfortunately, anybody that writes exceptions in Cocoa with the intent that you will catch them probably does not understand the issues well enough to implement a solid unwind implementation (e.g. even if it produces leaks, it's not solid).

3) That's really not the time or place to display an alert. If you install a top level exception handler (via NSSetUncaughtExceptionHandler) - You should simply log a message -- then the exception handler will abort. Your app is in an unstable state -- continuing is worse than aborting. You may want to send these custom messages home, it's best to do so at the next launch of your app.

4) In the majority of cases, your app is in an unstable state and you should not continue. But, to actually answer it for those corner cases: "Yes, you can recover and continue when you catch, but you should only attempt to recover and continue when the throwing API states that recovery is supported. If the problem is beyond your control, and the problem is not exceptional (e.g. file not found), and the vendor really expects you to continue, then I would have to assume that they expect you to continue, even though it really isn't (100% safe).". Do not attempt to recover/continue from within your top level exception handler (the program will abort after it returns). If you want to be very fancy and present that immediately on OSX, another process would be best. If you are calling through a pure C++ interface, then the unwinding is well defined, and the need to catch is necessary - do continue if it is recoverable. Exceptions in C++ can be recoverable and well defined - they are also used quite extensively (including less than exceptional conditions).

(IMO...) Exceptions in ObjC should not have been introduced, and any method that throws from system or third party libraries should be deprecated. They don't unwind well, or in a well defined manner. As well, unwinding flows against normal Cocoa program flow. That means that touching any objc object's memory/relations that was in mutation at the time of the throw and which lies between the throw and the catch is as good as undefined behaviour. Problem is - you have no idea what that memory is (in most cases, and within reasonable maintenance time). C++ exceptions are well defined, and they unwind correctly (e.g. destructors are called) - but trying to continue in an ObjC context is ignoring any consequences of undefined behavior. IMO, they should only exist for ObjC++ (because C++ requires them).

In an ideal world, your ObjC programs and the libraries you use would not use exceptions (at all). Since you use libraries that do throw (including Cocoa), install a top level exception handler only if you need some special information about the error. Where the API mandates that you could expect an exception thrown due to circumstances beyond your control and you are expected to recover, then write a catch but immediately convert that logic to normal program flow (e.g. NSError) - you never need to write your own throw. -[NSArray objectAtIndex: and "object does not respond to selector" are examples of programmer errors - they should not be caught, but the program should be corrected.



Related Topics



Leave a reply



Submit