#if NET20 || NET30 || NET35 || !NET_4_6 // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. /*============================================================ ** ** ** ** Purpose: The contract class allows for expressing preconditions, ** postconditions, and object invariants about methods in source ** code for runtime checking & static analysis. ** ** Two classes (Contract and ContractHelper) are split into partial classes ** in order to share the public front for multiple platforms (this file) ** while providing separate implementation details for each platform. ** ===========================================================*/ #define DEBUG // The behavior of this contract library should be consistent regardless of build type. using System.Collections.Generic; using System.Runtime.ConstrainedExecution; namespace System.Diagnostics.Contracts { /// /// Contains static methods for representing program contracts such as preconditions, postconditions, and invariants. /// /// /// WARNING: A binary rewriter must be used to insert runtime enforcement of these contracts. /// Otherwise some contracts like Ensures can only be checked statically and will not throw exceptions during runtime when contracts are violated. /// Please note this class uses conditional compilation to help avoid easy mistakes. Defining the preprocessor /// symbol CONTRACTS_PRECONDITIONS will include all preconditions expressed using Contract.Requires in your /// build. The symbol CONTRACTS_FULL will include postconditions and object invariants, and requires the binary rewriter. /// public static partial class Contract { /// /// In debug builds, perform a runtime check that is true. /// /// Expression to check to always be true. [Conditional("DEBUG")] [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Assert(bool condition) { if (!condition) { ReportFailure(ContractFailureKind.Assert, null, null, null); } } /// /// In debug builds, perform a runtime check that is true. /// /// Expression to check to always be true. /// If it is not a constant string literal, then the contract may not be understood by tools. [Conditional("DEBUG")] [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Assert(bool condition, string userMessage) { if (!condition) { ReportFailure(ContractFailureKind.Assert, userMessage, null, null); } } /// /// Instructs code analysis tools to assume the expression is true even if it can not be statically proven to always be true. /// /// Expression to assume will always be true. /// /// At runtime this is equivalent to an . /// [Conditional("DEBUG")] [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Assume(bool condition) { if (!condition) { ReportFailure(ContractFailureKind.Assume, null, null, null); } } /// /// Instructs code analysis tools to assume the expression is true even if it can not be statically proven to always be true. /// /// Expression to assume will always be true. /// If it is not a constant string literal, then the contract may not be understood by tools. /// /// At runtime this is equivalent to an . /// [Conditional("DEBUG")] [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Assume(bool condition, string userMessage) { if (!condition) { ReportFailure(ContractFailureKind.Assume, userMessage, null, null); } } /// /// Marker to indicate the end of the contract section of a method. /// [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static void EndContractBlock() { // Empty } /// /// Specifies a public contract such that the expression will be true when the enclosing method or property returns normally. /// /// Boolean expression representing the contract. May include and . /// /// This call must happen at the beginning of a method or property before any other code. /// This contract is exposed to clients so must only reference members at least as visible as the enclosing method. /// The contract rewriter must be used for runtime enforcement of this postcondition. /// [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Ensures(bool condition) { GC.KeepAlive(condition); AssertMustUseRewriter(ContractFailureKind.Postcondition, "Ensures"); } /// /// Specifies a public contract such that the expression will be true when the enclosing method or property returns normally. /// /// Boolean expression representing the contract. May include and . /// If it is not a constant string literal, then the contract may not be understood by tools. /// /// This call must happen at the beginning of a method or property before any other code. /// This contract is exposed to clients so must only reference members at least as visible as the enclosing method. /// The contract rewriter must be used for runtime enforcement of this postcondition. /// [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Ensures(bool condition, string userMessage) { GC.KeepAlive(condition); GC.KeepAlive(userMessage); AssertMustUseRewriter(ContractFailureKind.Postcondition, "Ensures"); } /// /// Specifies a contract such that if an exception of type is thrown then the expression will be true when the enclosing method or property terminates abnormally. /// /// Type of exception related to this postcondition. /// Boolean expression representing the contract. May include and . /// /// This call must happen at the beginning of a method or property before any other code. /// This contract is exposed to clients so must only reference types and members at least as visible as the enclosing method. /// The contract rewriter must be used for runtime enforcement of this postcondition. /// [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void EnsuresOnThrow(bool condition) where TException : Exception { GC.KeepAlive(typeof(TException)); GC.KeepAlive(condition); AssertMustUseRewriter(ContractFailureKind.PostconditionOnException, "EnsuresOnThrow"); } /// /// Specifies a contract such that if an exception of type is thrown then the expression will be true when the enclosing method or property terminates abnormally. /// /// Type of exception related to this postcondition. /// Boolean expression representing the contract. May include and . /// If it is not a constant string literal, then the contract may not be understood by tools. /// /// This call must happen at the beginning of a method or property before any other code. /// This contract is exposed to clients so must only reference types and members at least as visible as the enclosing method. /// The contract rewriter must be used for runtime enforcement of this postcondition. /// [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void EnsuresOnThrow(bool condition, string userMessage) where TException : Exception { GC.KeepAlive(typeof(TException)); GC.KeepAlive(condition); GC.KeepAlive(userMessage); AssertMustUseRewriter(ContractFailureKind.PostconditionOnException, "EnsuresOnThrow"); } /// /// Returns whether the returns true /// for any integer starting from to - 1. /// /// First integer to pass to . /// One greater than the last integer to pass to . /// Function that is evaluated from to - 1. /// true if returns true for any integer /// starting from to - 1. /// [Pure] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] // Assumes predicate obeys CER rules. public static bool Exists(int fromInclusive, int toExclusive, Predicate predicate) { if (fromInclusive > toExclusive) { throw new ArgumentException("fromInclusive must be less than or equal to toExclusive."); } if (predicate == null) { throw new ArgumentNullException("predicate"); } EndContractBlock(); for (var i = fromInclusive; i < toExclusive; i++) { if (predicate(i)) { return true; } } return false; } /// /// Returns whether the returns true /// for any element in the . /// /// The type that is contained in collection. /// The collection from which elements will be drawn from to pass to . /// Function that is evaluated on elements from . /// true if and only if returns true for an element in /// . /// [Pure] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] // Assumes predicate & collection enumerator obey CER rules. public static bool Exists(IEnumerable collection, Predicate predicate) { if (collection == null) { throw new ArgumentNullException("collection"); } if (predicate == null) { throw new ArgumentNullException("predicate"); } EndContractBlock(); foreach (var t in collection) { if (predicate(t)) { return true; } } return false; } /// /// Returns whether the returns true /// for all integers starting from to - 1. /// /// First integer to pass to . /// One greater than the last integer to pass to . /// Function that is evaluated from to - 1. /// true if returns true for all integers /// starting from to - 1. /// [Pure] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] // Assumes predicate obeys CER rules. public static bool ForAll(int fromInclusive, int toExclusive, Predicate predicate) { if (fromInclusive > toExclusive) { throw new ArgumentException("fromInclusive must be less than or equal to toExclusive."); } if (predicate == null) { throw new ArgumentNullException("predicate"); } EndContractBlock(); for (var i = fromInclusive; i < toExclusive; i++) { if (!predicate(i)) { return false; } } return true; } /// /// Returns whether the returns true /// for all elements in the . /// /// The type that is contained in collection. /// The collection from which elements will be drawn from to pass to . /// Function that is evaluated on elements from . /// true if and only if returns true for all elements in /// . /// [Pure] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] // Assumes predicate & collection enumerator obey CER rules. public static bool ForAll(IEnumerable collection, Predicate predicate) { if (collection == null) { throw new ArgumentNullException("collection"); } if (predicate == null) { throw new ArgumentNullException("predicate"); } EndContractBlock(); foreach (var t in collection) { if (!predicate(t)) { return false; } } return true; } /// /// Specifies a contract such that the expression will be true after every method or property on the enclosing class. /// /// Boolean expression representing the contract. /// /// This contact can only be specified in a dedicated invariant method declared on a class. /// This contract is not exposed to clients so may reference members less visible as the enclosing method. /// The contract rewriter must be used for runtime enforcement of this invariant. /// [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Invariant(bool condition) { GC.KeepAlive(condition); AssertMustUseRewriter(ContractFailureKind.Invariant, "Invariant"); } /// /// Specifies a contract such that the expression will be true after every method or property on the enclosing class. /// /// Boolean expression representing the contract. /// If it is not a constant string literal, then the contract may not be understood by tools. /// /// This contact can only be specified in a dedicated invariant method declared on a class. /// This contract is not exposed to clients so may reference members less visible as the enclosing method. /// The contract rewriter must be used for runtime enforcement of this invariant. /// [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Invariant(bool condition, string userMessage) { GC.KeepAlive(condition); GC.KeepAlive(userMessage); AssertMustUseRewriter(ContractFailureKind.Invariant, "Invariant"); } /// /// Represents the value of as it was at the start of the method or property. /// /// Type of . This can be inferred. /// Value to represent. This must be a field or parameter. /// Value of at the start of the method or property. /// /// This method can only be used within the argument to the contract. /// [Pure] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static T OldValue(T value) { GC.KeepAlive(value); return default(T); } /// /// Specifies a contract such that the expression must be true before the enclosing method or property is invoked. /// /// Boolean expression representing the contract. /// /// This call must happen at the beginning of a method or property before any other code. /// This contract is exposed to clients so must only reference members at least as visible as the enclosing method. /// Use this form when backward compatibility does not force you to throw a particular exception. /// [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Requires(bool condition) { GC.KeepAlive(condition); AssertMustUseRewriter(ContractFailureKind.Precondition, "Requires"); } /// /// Specifies a contract such that the expression must be true before the enclosing method or property is invoked. /// /// Boolean expression representing the contract. /// If it is not a constant string literal, then the contract may not be understood by tools. /// /// This call must happen at the beginning of a method or property before any other code. /// This contract is exposed to clients so must only reference members at least as visible as the enclosing method. /// Use this form when backward compatibility does not force you to throw a particular exception. /// [Conditional("CONTRACTS_FULL")] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Requires(bool condition, string userMessage) { GC.KeepAlive(condition); GC.KeepAlive(userMessage); AssertMustUseRewriter(ContractFailureKind.Precondition, "Requires"); } /// /// Specifies a contract such that the expression must be true before the enclosing method or property is invoked. /// /// The exception to throw if the condition is false. /// Boolean expression representing the contract. /// /// This call must happen at the beginning of a method or property before any other code. /// This contract is exposed to clients so must only reference members at least as visible as the enclosing method. /// Use this form when you want to throw a particular exception. /// [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Requires(bool condition) where TException : Exception { GC.KeepAlive(typeof(TException)); GC.KeepAlive(condition); AssertMustUseRewriter(ContractFailureKind.Precondition, "Requires"); } /// /// Specifies a contract such that the expression must be true before the enclosing method or property is invoked. /// /// The exception to throw if the condition is false. /// Boolean expression representing the contract. /// If it is not a constant string literal, then the contract may not be understood by tools. /// /// This call must happen at the beginning of a method or property before any other code. /// This contract is exposed to clients so must only reference members at least as visible as the enclosing method. /// Use this form when you want to throw a particular exception. /// [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public static void Requires(bool condition, string userMessage) where TException : Exception { GC.KeepAlive(typeof(TException)); GC.KeepAlive(condition); GC.KeepAlive(userMessage); AssertMustUseRewriter(ContractFailureKind.Precondition, "Requires"); } /// /// Represents the result (a.k.a. return value) of a method or property. /// /// Type of return value of the enclosing method or property. /// Return value of the enclosing method or property. /// /// This method can only be used within the argument to the contract. /// [Pure] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static T Result() { return default(T); } /// /// Represents the final (output) value of an out parameter when returning from a method. /// /// Type of the out parameter. /// The out parameter. /// The output value of the out parameter. /// /// This method can only be used within the argument to the contract. /// [Pure] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static T ValueAtReturn(out T value) { value = default(T); return value; } } } #endif