What is clean does depend on a lot of factors. A general exception handler via PostSharp or other AOP handlers e.g. the Exception Handling Application Block from the Enterprise Library does even let you configure your policy. Although a nice idea it has never gained much traction until the policy injecion application block was in place which is also an AOP framework which would allow you to handle exceptions centrally in a configurable way.
However in reality exception handling remains hard. The first rule should be to never hide exceptions. You can catch them of course but you should always log them when you do not let them propagate further. What if your GenericLibrary uses some config file to decide in which locale the integers should be processed and it does not find its config file? You get repeated errors but you will never find out the root cause until you debug it because you throw away the exception object and return a string instead.
An equally bad "handling" strategy is to to
catch(Exception ex)
{
Log("Error has occured: {0}", ex.Message);
}
This will give you the error messsage but you loose the complete call stack and any inner exceptions. This is especially bad if you receive some generic wrapper exception like TargetInvocationException which contains only a generic error message.
The right handling strategy depends quite much on your specific context. If you mean with console application a small application which is not delivered to customers then it is usually the simpliest to remove all catch handlers in a first pass and handle them globally in the main method. Then when you have got experience with the most common non fatal errors you can re add the necessary catch handlers to regain robustness. Now you continue to work on non fatal errors but you keep the failfast strategy for the fatal ones.
Any previous answer here does only give you the advice to use this or that strategy but you need to decide which exceptions are non critical to your app on a case by case basis. When you catch everything you won´t find out why your app did nothing because of internally catched errors. If you have no handling at all your app will terminate on every non fatal error (e.g. it can be ok to return 0 if the value cannot be parsed in your app).
For a small console app I would
- Remove all catch blocks
- Even in the Main method
This way you get automatic logging of the .NET Framework in the application event log with no extra effort if your app does crash. If your console app is executed e.g. as a scheduled job printing the output to the console will not help you much. This is the cleanest way of handling exceptions: No handling at all and let your application crash so you can find out what went wrong in the application event log.
If you deploy besides your executable the pdbs for release builds you also get the line numbers and file infos which makes it really easy to spot the error in most cases.
If your application is mission critical or delivered to customers it can happen that you
need to employ some logging framework to log to some private log file. The difference between a console application and a windows application is only a flag in the PE header.
A Windows application will detach from the currently started console whereas a console application will remain attached to it. That is the only difference. You can also create a WPF application in a console application but it will block your console as long as it will run which is perhaps not the thing you did want.
But if you switch to a Windows application you can allocate a new console to make Console.WriteLine happen to work again and you can continue to use printf debugging which is perhaps the most used debugging method although a quite old fashioned one.
Usually you would add a tracing library to your application to follow your application flow which is by default off. Logging should also be done which is always on which does only error logging. With that approach you have more troublesshooting options at customer machines if error logging is not enough.