I was having a Skype conversation with Pete Brown and he said “Why don't you blog this stuff, or set up a GitHub project or something with these things?”. I told him, “well, actually, I just started blogging!”
That conversation gave me a figurative kick in the tuchus, so I decided to share a small nugget.
Defensive Development
- Checking all your assumptions
- Checking all your parameters for null or incorrect values
- Verifying things like loop invariants, preconditions, postconditions, http://en.wikipedia.org/wiki/Code_contract, etc
Given that I think like this, I tend to use debug assertions a lot.
Debug.Assert
So, Debug.Assert is useful, but, what about Release mode?
What about Release Mode?
I think this is Utopian in this day and age.
For the large majority of developers, extreme performance is not a problem. A few exceptions would be developers who work on:
- BIG games (not words with friends, more like Call Of Duty)
- Operating Systems
- Low-level Device Drivers
Release.Assert?
Of course, you wouldn’t run Debug code in Production either… Right? RIGHT?
So, our only option is Exceptions.
My Solution
- continue to utilize Debug.Assert
- In Release Mode, throw an exception instead.
- Allow for custom exception usage (can’t just throw one kind of exception)
[SuppressMessage("Microsoft.Design", "CA1004", Justification = "This method instantiates and throws the exception, it can't be passed in")] [DebuggerStepThrough()] public static void AssertThrow<TException>(bool condition, string failureMessage) where TException : Exception { Debug.Assert(condition, failureMessage); if (condition == false) { // throw exception here... } }The [SuppressMessage] is there in case you’re running Code Analysis. The analysis tools don’t like that the method is using a generic type that’s not part of the rest of the function signature.
The [DebuggerStepThrough] just makes it so that it steps over this as if it’s one execution statement when debugging.
The Debug.Assert line is rather obvious, so I’ll skip that.
The "where TException : Exception" part forces the type you specify to be a derived class of System.Exception, so it can be thrown.
The next section is where we throw the exception.
ConstructorInfo ctor = typeof(TException).GetConstructor( new Type[] { typeof(string) }); TException ex = (TException)ctor.Invoke(new object[] { failureMessage }); throw ex;
I’m using Reflection to get the constructor of the TException object that takes one string. Then, I am invoking that constructor with the failureMessage and throwing the exception.
So, all you do is call it like this:
void Foo(Bar bar) { Diag.AssertThrow<ArgumentNullException>( bar != null, "Duh, Foo needs a Bar!"); // use bar here. }
Teh Codez
using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace McKearney.Common.Diagnostics { /// <summary> /// Utility class that contains Diagnostic- and Instrumentation-related methods /// </summary> public static class Diag { #region Static Operations /// <summary> /// Asserts and then throws, making sure that the error gets handled by client code /// </summary> /// <typeparam name="TException">The type of the exception to throw.</typeparam> /// <param name="condition">the asserted condition</param> /// <param name="failureMessage">The failure message.</param> [SuppressMessage("Microsoft.Design", "CA1004", Justification = "This method instantiates and throws the exception, it can't be passed in")] [DebuggerStepThrough()] public static void AssertThrow<texception>(bool condition, string failureMessage) where TException : Exception { Debug.Assert(condition, failureMessage); if (condition == false) { ConstructorInfo ctor = typeof(TException).GetConstructor(new Type[] { typeof(string) }); TException ex = (TException)ctor.Invoke(new object[] { failureMessage }); throw ex; } } } }
Leave me a comment, I'm curious what your thoughts are.
No comments:
Post a Comment