I am working on a fairly complex .NET application that interacts with another application. Many single-line statements are possible culprits for throwing an Exception and there is often nothing I can do to check the state before executing them to prevent these Exceptions.The question is, based on best practices and seasoned experience, how frequently should I lace my code with try/catch blocks? I've listed three examples below, but I'm open to any advice.I'm really hoping to get some pros/cons of various approaches. I can certainly come up with some of my own (greater log granularity for the O-C approach, better performance for the Monolithic approach), so I'm looking for experience over opinion.EDIT: I should add that this application is a batch program. The only recovery necessary in most cases is to log the error, clean up gracefully, and quit. So this could be seen to be as much a question of log granularity as exception handling. In my mind's eye I can imagine good reasons for both, so I'm looking for some general advice to help me find an appropriate balance.Monolitich Approachclass Program{    public static void Main(){        try{            Step1();            Step2();            Step3();        } catch (Exception e) {            Log(e);        } finally {            CleanUp();        }    }    public static void Step1(){        ExternalApp.Dangerous1();        ExternalApp.Dangerous2();    }    public static void Step2(){        ExternalApp.Dangerous3();        ExternalApp.Dangerous4();    }    public static void Step3(){        ExternalApp.Dangerous5();        ExternalApp.Dangerous6();    }}Delegated Approachclass Program{    public static void Main(){        try{            Step1();            Step2();            Step3();        } finally {            CleanUp();        }    }    public static void Step1(){        try{            ExternalApp.Dangerous1();            ExternalApp.Dangerous2();        } catch (Exception e) {            Log(e);            throw;        }    }    public static void Step2(){        try{            ExternalApp.Dangerous3();            ExternalApp.Dangerous4();        } catch (Exception e) {            Log(e);            throw;        }    }    public static void Step3(){        try{            ExternalApp.Dangerous5();            ExternalApp.Dangerous6();        } catch (Exception e) {            Log(e);            throw;        }    }}Obsessive-Compulsive Approachclass Program{    public static void Main(){        try{            Step1();            Step2();            Step3();        } finally {            CleanUp();        }    }    public static void Step1(){        try{            ExternalApp.Dangerous1();        } catch (Exception e) {            Log(e);            throw;        }        try{            ExternalApp.Dangerous2();        } catch (Exception e) {            Log(e);            throw;        }    }    public static void Step2(){        try{            ExternalApp.Dangerous3();        } catch (Exception e) {            Log(e);            throw;        }        try{            ExternalApp.Dangerous4();        } catch (Exception e) {            Log(e);            throw;        }    }    public static void Step3(){        try{            ExternalApp.Dangerous5();        } catch (Exception e) {            Log(e);            throw;        }        try{            ExternalApp.Dangerous6();        } catch (Exception e) {            Log(e);            throw;        }    }}Other approaches welcomed and encouraged. Above are examples only.
Exception Handling Frequency/Log Detail
c#;.net;programming practices;logging;exception handling
Catch at the granularity that is meaningful to your application. If you are not going to take a different action for a different exception source, then there is no need to break those things apart.