\input{exceptions_and_using_head.tex} \begin{document} \raggedright \pagestyle{fancy} \begin{slide} \begin{center} {\color{title}\bf \Huge \FileTitle{}}\\ \vspace{1ex} {\large\textit{\FileAuthor{}}}\\ {\scriptsize\url{http://slog.dk/svn/home/jensen/exceptions_and_using/}}\\ \fbox{ \begin{minipage}{.7\textwidth} \ptsize{8} \VerbatimInput[fontsize=\tiny]{.svninfo} \VerbatimInput[fontsize=\tiny]{.svnstatus} \end{minipage}} \end{center} \end{slide} \begin{slide} \slideheading{Original code} \begin{CS} public bool LoadActiveReadings() { bool res = false; try { fs = new System.IO.FileStream("ActiveJobs.xml", System.IO.FileMode.Open); ActiveJobs =(System.Collections.ArrayList)Serializer.Deserialize(fs); } catch (System.IO.FileNotFoundException ex) { string MakesCompilerGiveNoWarning = ex.Message; // This error will be thrown if ActiveJobs.xml file doesnt exist. } catch (System.InvalidOperationException ex) { KsLog.Log.Info("Invalid ActiveJobs.xml file"); fs.Close(); fs = null; } if (fs != null) { fs.Close(); res = true; } return res; } \end{CS} \end{slide} \begin{slide} \slideheading{Analysis} \begin{itemize} \item Catches on a lot of code (well... more than required) \item Hides inconsistency (``Invalid ActiveJobs.xml'') \item Has ``return-varable'' \item Converts exception to success indicating bool \begin{itemize} \item Tells caller if success, not why failure \item Has a default for failure \end{itemize} \item Spreads cleanup (\cscode{Close}) \item Uses instance-variable as local \end{itemize} \end{slide} \begin{slide} \slideheading{Catch Closely} \begin{CS} public bool LoadActiveReadings() { try { fs = new System.IO.FileStream("ActiveJobs.xml", System.IO.FileMode.Open); } catch (System.IO.FileNotFoundException) { return false; } bool res = false; try { ActiveJobs = System.Collections.ArrayList)Serializer.Deserialize(fs); } catch (System.InvalidOperationException ex) { KsLog.Log.Info("Invalid ActiveJobs.xml file"); fs.Close(); fs = null; } if (fs != null) { fs.Close(); res = true; } return res; } \end{CS} \end{slide} \begin{slide} \slideheading{Return on Error} \begin{CS} public bool LoadActiveReadings() { try { fs = new System.IO.FileStream("ActiveJobs.xml", System.IO.FileMode.Open); } catch (System.IO.FileNotFoundException) { return false; } try { ActiveJobs =(System.Collections.ArrayList)Serializer.Deserialize(fs); } catch (System.InvalidOperationException ex) { KsLog.Log.Info("Invalid ActiveJobs.xml file"); fs.Close(); return false; } fs.Close(); return true; } \end{CS} \end{slide} \begin{slide} \slideheading{Use finally for cleanup} \begin{CS} public bool LoadActiveReadings() { try { fs = new System.IO.FileStream("ActiveJobs.xml", System.IO.FileMode.Open); } catch (System.IO.FileNotFoundException) { return false; } try { ActiveJobs =(System.Collections.ArrayList)Serializer.Deserialize(fs); } catch (System.InvalidOperationException ex) { KsLog.Log.Info("Invalid ActiveJobs.xml file"); return false; } finally { fs.Close(); } return true; } \end{CS} \end{slide} \begin{slide} \slideheading{Don't hide inconsistency from caller} Well, you can dicuss this actual case, but missing != inconsistent \begin{CS} public bool LoadActiveReadings() { try { fs = new System.IO.FileStream("ActiveJobs.xml", System.IO.FileMode.Open); } catch (System.IO.FileNotFoundException) { return false; } try { ActiveJobs =(System.Collections.ArrayList)Serializer.Deserialize(fs); } finally { fs.Close(); } return true; } \end{CS} \end{slide} \begin{slide} \slideheading{Use locals for local} \begin{CS} public bool LoadActiveReadings() { Stream fs; try { fs = new System.IO.FileStream("ActiveJobs.xml", System.IO.FileMode.Open); } catch (System.IO.FileNotFoundException) { return false; } try { ActiveJobs =(System.Collections.ArrayList)Serializer.Deserialize(fs); } finally { fs.Close(); } return true; } \end{CS} \end{slide} \begin{slide} \slideheading{Use using for IDisposable's} \begin{CS} public bool LoadActiveReadings() { Stream fs; try { fs = new System.IO.FileStream("ActiveJobs.xml", System.IO.FileMode.Open); } catch (System.IO.FileNotFoundException) { return false; } using ( fs ) { ActiveJobs =(System.Collections.ArrayList)Serializer.Deserialize(fs); } return true; } \end{CS} \end{slide} \begin{slide} \slideheading{Without bool return} \begin{CS} public void LoadActiveReadings() { Stream fs; try { fs = new System.IO.FileStream("ActiveJobs.xml"); } catch (System.IO.FileNotFoundException) { return; } using ( fs ) { ActiveJobs =(System.Collections.ArrayList)Serializer.Deserialize(fs); } } \end{CS} \end{slide} \begin{slide} \slideheading{When to catch?} \begin{itemize} \item When you can do something about the error \begin{itemize} \item retry \item default \item alternate method \end{itemize} \item At the top-level \begin{itemize} \item main \item new threads \item multi-cast delegates \end{itemize} \end{itemize} \end{slide} \begin{slide} \slideheading{A pattern for Main} \begin{CS} static int _Main(string[] args) { // The real Main } static int Main(string[] args) { #if !DEBUG try { #endif _Main(args); #if !DEBUG } catch ( Exception e ) { KsLog.log.ERROR(e); throw; } #endif } \end{CS} \end{slide} \begin{slide} \slideheading{Using} \begin{itemize} \item \lstinline[language={[jensen]Csharp},style=basichighlight]!using ( o ) { ... }! \item \lstinline[language={[jensen]Csharp},style=basichighlight]!using ( TYPE o = e ) { ... }! \item \lstinline[language={[jensen]Csharp},style=basichighlight]!using ( TYPE l1 = e1, l2 = e2 ) { ... }! \end{itemize} \begin{CS} TYPE o = null; try { o = e1; } finally { if ( e1 != null ) o.Dispose(); } \end{CS} Also in C\#: \begin{itemize} \item \lstinline[language={[jensen]Csharp},style=basichighlight]!lock ( [TYPE o =] e) { ... }! \item \lstinline[language={[jensen]Csharp},style=basichighlight]!fixed (T* t = e) { ... }! \end{itemize} \end{slide} \begin{slide} \slideheading{Implementing resouces} \begin{CS} public class Resource: IDisposable { ~Resource() { if ( ... ) { /* not closed */ KsLog.Log.WARNING("Forgot Close on Resource: " + this.ToString()); Close(); } } void Close() { GC.SuppressFinalize(this); ... /* do stuff to close */ } void Dispose() { Close(); } } \end{CS} \end{slide} \begin{slide} \slideheading{Conclusion} \begin{itemize} \item Only catch (either of): \begin{itemize} \item What you can handle \item At stack-top level \end{itemize} \item When you catch, catch on a small region \item Use using where possible \begin{itemize} \item \emph{many classes support \cscode{IDispoable}} \end{itemize} \item Resources should be \cscode{IDisposable} \item Exceptions-safety doesn't make programs longer or harder to read \item Returning errors (usually) makes code simpler than return-vars \item Throwing makes code even simpler \end{itemize} \end{slide} \end{document}