// from: http://www.codeproject.com/Articles/1863/Design-by-Contract-Framework // Provides support for Design By Contract // as described by Bertrand Meyer in his seminal book, // Object-Oriented Software Construction (2nd Ed) Prentice Hall 1997 // (See chapters 11 and 12). // // See also Building Bug-free O-O Software: An Introduction to Design by Contract // http://www.eiffel.com/doc/manuals/technology/contract/ // // The following conditional compilation symbols are supported: // // These suggestions are based on Bertrand Meyer's Object-Oriented Software Construction (2nd Ed) p393 // // DBC_CHECK_ALL - Check assertions - implies checking preconditions, postconditions and invariants // DBC_CHECK_INVARIANT - Check invariants - implies checking preconditions and postconditions // DBC_CHECK_POSTCONDITION - Check postconditions - implies checking preconditions // DBC_CHECK_PRECONDITION - Check preconditions only, e.g., in Release build // // A suggested default usage scenario is the following: // // #if DEBUG // #define DBC_CHECK_ALL // #else // #define DBC_CHECK_PRECONDITION // #endif // // Alternatively, you can define these in the project properties dialog. #if DEBUG && !PROFILER #define DBC_CHECK_ALL #endif using System; using System.Diagnostics; namespace DesignByContract { /// /// Design By Contract Checks. /// /// Each method generates an exception or /// a trace assertion statement if the contract is broken. /// /// /// This example shows how to call the Require method. /// Assume DBC_CHECK_PRECONDITION is defined. /// /// public void Test(int x) /// { /// try /// { /// Check.Require(x > 1, "x must be > 1"); /// } /// catch (System.Exception ex) /// { /// Console.WriteLine(ex.ToString()); /// } /// } /// /// If you wish to use trace assertion statements, intended for Debug scenarios, /// rather than exception handling then set /// /// Check.UseAssertions = true /// /// You can specify this in your application entry point and maybe make it /// dependent on conditional compilation flags or configuration file settings, e.g., /// /// #if DBC_USE_ASSERTIONS /// Check.UseAssertions = true; /// #endif /// /// You can direct output to a Trace listener. For example, you could insert /// /// Trace.Listeners.Clear(); /// Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); /// /// /// or direct output to a file or the Event Log. /// /// (Note: For ASP.NET clients use the Listeners collection /// of the Debug, not the Trace, object and, for a Release build, only exception-handling /// is possible.) /// /// public sealed class Check { #region Interface /// /// Precondition check. /// [Conditional("DBC_CHECK_ALL"), Conditional("DBC_CHECK_INVARIANT"), Conditional("DBC_CHECK_POSTCONDITION"), Conditional("DBC_CHECK_PRECONDITION")] public static void Require(bool assertion, string message) { if (UseExceptions) { if (!assertion) throw new PreconditionException(message); } else { Trace.Assert(assertion, "Precondition: " + message); } } /// /// Precondition check. /// [Conditional("DBC_CHECK_ALL"), Conditional("DBC_CHECK_INVARIANT"), Conditional("DBC_CHECK_POSTCONDITION"), Conditional("DBC_CHECK_PRECONDITION")] public static void Require(bool assertion, string message, Exception inner) { if (UseExceptions) { if (!assertion) throw new PreconditionException(message, inner); } else { Trace.Assert(assertion, "Precondition: " + message); } } /// /// Precondition check. /// [Conditional("DBC_CHECK_ALL"), Conditional("DBC_CHECK_INVARIANT"), Conditional("DBC_CHECK_POSTCONDITION"), Conditional("DBC_CHECK_PRECONDITION")] public static void Require(bool assertion) { if (UseExceptions) { if (!assertion) throw new PreconditionException("Precondition failed."); } else { Trace.Assert(assertion, "Precondition failed."); } } /// /// Postcondition check. /// [Conditional("DBC_CHECK_ALL"), Conditional("DBC_CHECK_INVARIANT"), Conditional("DBC_CHECK_POSTCONDITION")] public static void Ensure(bool assertion, string message) { if (UseExceptions) { if (!assertion) throw new PostconditionException(message); } else { Trace.Assert(assertion, "Postcondition: " + message); } } /// /// Postcondition check. /// [Conditional("DBC_CHECK_ALL"), Conditional("DBC_CHECK_INVARIANT"), Conditional("DBC_CHECK_POSTCONDITION")] public static void Ensure(bool assertion, string message, Exception inner) { if (UseExceptions) { if (!assertion) throw new PostconditionException(message, inner); } else { Trace.Assert(assertion, "Postcondition: " + message); } } /// /// Postcondition check. /// [Conditional("DBC_CHECK_ALL"), Conditional("DBC_CHECK_INVARIANT"), Conditional("DBC_CHECK_POSTCONDITION")] public static void Ensure(bool assertion) { if (UseExceptions) { if (!assertion) throw new PostconditionException("Postcondition failed."); } else { Trace.Assert(assertion, "Postcondition failed."); } } /// /// Invariant check. /// [Conditional("DBC_CHECK_ALL"), Conditional("DBC_CHECK_INVARIANT")] public static void Invariant(bool assertion, string message) { if (UseExceptions) { if (!assertion) throw new InvariantException(message); } else { Trace.Assert(assertion, "Invariant: " + message); } } /// /// Invariant check. /// [Conditional("DBC_CHECK_ALL"), Conditional("DBC_CHECK_INVARIANT")] public static void Invariant(bool assertion, string message, Exception inner) { if (UseExceptions) { if (!assertion) throw new InvariantException(message, inner); } else { Trace.Assert(assertion, "Invariant: " + message); } } /// /// Invariant check. /// [Conditional("DBC_CHECK_ALL"), Conditional("DBC_CHECK_INVARIANT")] public static void Invariant(bool assertion) { if (UseExceptions) { if (!assertion) throw new InvariantException("Invariant failed."); } else { Trace.Assert(assertion, "Invariant failed."); } } /// /// Assertion check. /// [Conditional("DBC_CHECK_ALL")] public static void Assert(bool assertion, string message) { if (UseExceptions) { if (!assertion) throw new AssertionException(message); } else { Trace.Assert(assertion, "Assertion: " + message); } } /// /// Assertion check. /// [Conditional("DBC_CHECK_ALL")] public static void Assert(bool assertion, string message, Exception inner) { if (UseExceptions) { if (!assertion) throw new AssertionException(message, inner); } else { Trace.Assert(assertion, "Assertion: " + message); } } /// /// Assertion check. /// [Conditional("DBC_CHECK_ALL")] public static void Assert(bool assertion) { if (UseExceptions) { if (!assertion) throw new AssertionException("Assertion failed."); } else { Trace.Assert(assertion, "Assertion failed."); } } /// /// Set this if you wish to use Trace Assert statements /// instead of exception handling. /// (The Check class uses exception handling by default.) /// public static bool UseAssertions { get { return useAssertions; } set { useAssertions = value; } } #endregion // Interface #region Implementation // No creation private Check() {} /// /// Is exception handling being used? /// private static bool UseExceptions { get { return !useAssertions; } } // Are trace assertion statements being used? // Default is to use exception handling. private static bool useAssertions = false; #endregion // Implementation } // End Check internal class Trace { internal static void Assert(bool assertion, string v) { #if NETFX_CORE System.Diagnostics.Contracts.Contract.Assert(assertion, v); #else System.Diagnostics.Trace.Assert(assertion, v); #endif } } #region Exceptions /// /// Exception raised when a contract is broken. /// Catch this exception type if you wish to differentiate between /// any DesignByContract exception and other runtime exceptions. /// /// public class DesignByContractException : ApplicationException { protected DesignByContractException() {} protected DesignByContractException(string message) : base(message) {} protected DesignByContractException(string message, Exception inner) : base(message, inner) {} } /// /// Exception raised when a precondition fails. /// public class PreconditionException : DesignByContractException { /// /// Precondition Exception. /// public PreconditionException() {} /// /// Precondition Exception. /// public PreconditionException(string message) : base(message) {} /// /// Precondition Exception. /// public PreconditionException(string message, Exception inner) : base(message, inner) {} } /// /// Exception raised when a postcondition fails. /// public class PostconditionException : DesignByContractException { /// /// Postcondition Exception. /// public PostconditionException() {} /// /// Postcondition Exception. /// public PostconditionException(string message) : base(message) {} /// /// Postcondition Exception. /// public PostconditionException(string message, Exception inner) : base(message, inner) {} } /// /// Exception raised when an invariant fails. /// public class InvariantException : DesignByContractException { /// /// Invariant Exception. /// public InvariantException() {} /// /// Invariant Exception. /// public InvariantException(string message) : base(message) {} /// /// Invariant Exception. /// public InvariantException(string message, Exception inner) : base(message, inner) {} } /// /// Exception raised when an assertion fails. /// public class AssertionException : DesignByContractException { /// /// Assertion Exception. /// public AssertionException() {} /// /// Assertion Exception. /// public AssertionException(string message) : base(message) {} /// /// Assertion Exception. /// public AssertionException(string message, Exception inner) : base(message, inner) {} } #endregion // Exception classes } // End Design By Contract