Code Contracts + Code Analysis

前端 未结 2 2057
攒了一身酷
攒了一身酷 2021-02-05 06:56

I think about starting to use Code Contracts in my code base.

I already use Code Analysis with all rules enabled and a goal of zero warnings.

However, when using

2条回答
  •  北荒
    北荒 (楼主)
    2021-02-05 07:59

    As of Version 4.5.2 of the framework (possibly even 4.5) it is possible to tell Code Analysis about the contracts being enforced by Code Contracts. First create the following extension method and marker attribute

      using System;
      using System.Diagnostics;
      using System.Diagnostics.CodeAnalysis;
      using System.Diagnostics.Contracts;
    
      /// Extension methods to enhance Code Contracts and integration with Code Analysis.
      public static class ContractExtensions {
    #if RUNTIME_NULL_CHECKS
        /// Throws ArgumentNullException{name} if value is null.
        /// Value to be tested.
        /// Name of the parameter being tested, for use in the exception thrown.
        [ContractArgumentValidator]  // Requires Assemble Mode = Custom Parameter Validation
        public static void ContractedNotNull([ValidatedNotNull]this T value, string name) where T : class {
          if (value == null) throw new ArgumentNullException(name);
          Contract.EndContractBlock();
        }
    #else
        /// Throws ContractException{name} if value is null.
        /// Value to be tested.
        /// Name of the parameter being tested, for use in the exception thrown.
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value")]
        [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "name")]
        [ContractAbbreviator] // Requires Assemble Mode = Standard Contract Requires
        public static void ContractedNotNull([ValidatedNotNull]this T value, string name) where T : class {
          Contract.Requires(value != null,name);
        }
    #endif
      }
    
    /// Decorator for an incoming parameter that is contractually enforced as NotNull.
    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
    public sealed class ValidatedNotNullAttribute : global::System.Attribute {}
    

    and now convert your entry null-tests to the following format:

    /// IForEachable2{TItem} implementation
    public   void  ForEach(FastIteratorFunctor functor) {
      functor.ContractedNotNull("functor"); // for Code Analysis
    
      TItem[] array = _array;
      for (int i = 0; i < array.Length; i++)    functor.Invoke(array[i]);
    }
    

    The method name ContractedNotNull and the compilation switch RUNTIME_NULL_CHECKS can of course be changed to anything that suits your naming style.

    Here is the original blog that informed me of this technique, which I have refined slightly; many thanks to Terje Sandstrom for publishing his research.

    Rico Suter expands on this here by using additional attributes so that the debugger and inliner are smarter also:

    • DebuggerStepThroughAttribute class
    • MethodImplAttribute class

提交回复
热议问题