c# - Contratos de código+Análisis de código
.net visual-studio (2)
A partir de la versión 4.5.2 del marco (posiblemente incluso 4.5) es posible informarle a Code Analysis sobre los contratos que están siendo ejecutados por los contratos de código. Primero crea el siguiente método de extensión y atributo de marcador
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
/// <summary>Extension methods to enhance Code Contracts and integration with Code Analysis.</summary>
public static class ContractExtensions {
#if RUNTIME_NULL_CHECKS
/// <summary>Throws <c>ArgumentNullException{name}</c> if <c>value</c> is null.</summary>
/// <param name="value">Value to be tested.</param>
/// <param name="name">Name of the parameter being tested, for use in the exception thrown.</param>
[ContractArgumentValidator] // Requires Assemble Mode = Custom Parameter Validation
public static void ContractedNotNull<T>([ValidatedNotNull]this T value, string name) where T : class {
if (value == null) throw new ArgumentNullException(name);
Contract.EndContractBlock();
}
#else
/// <summary>Throws <c>ContractException{name}</c> if <c>value</c> is null.</summary>
/// <param name="value">Value to be tested.</param>
/// <param name="name">Name of the parameter being tested, for use in the exception thrown.</param>
[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<T>([ValidatedNotNull]this T value, string name) where T : class {
Contract.Requires(value != null,name);
}
#endif
}
/// <summary>Decorator for an incoming parameter that is contractually enforced as NotNull.</summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public sealed class ValidatedNotNullAttribute : global::System.Attribute {}
y ahora convierta su entrada en pruebas nulas al siguiente formato:
/// <summary>IForEachable2{TItem} implementation</summary>
public void ForEach(FastIteratorFunctor<TItem> functor) {
functor.ContractedNotNull("functor"); // for Code Analysis
TItem[] array = _array;
for (int i = 0; i < array.Length; i++) functor.Invoke(array[i]);
}
Por supuesto, el nombre del método ContractedNotNull y el interruptor de compilación RUNTIME_NULL_CHECKS se pueden cambiar a cualquier cosa que se adapte a su estilo de nomenclatura.
Aquí está el blog original que me informó de esta técnica, que he refinado levemente; Muchas gracias a Terje Sandstrom por publicar su investigación.
Rico Suter expande esto here usando atributos adicionales para que el depurador y el inliner sean más inteligentes también:
Pienso en comenzar a usar Contratos de Código en mi base de código.
Ya utilizo Code Analysis con todas las reglas habilitadas y un objetivo de cero advertencias.
Sin embargo, al usar Contract.Requires(parameter != null)
recibo una advertencia de Code Analysis, a saber CA1062:
CA1062: Microsoft.Design: en el método ''Foo'' visible externamente, valide el parámetro ''parámetro'' antes de usarlo.
Eso es desafortunado, no quiero deshabilitar esa regla ya que la encuentro útil. Pero tampoco quiero suprimir cada falsa ocurrencia de ello.
¿Hay una solución?
Para resolver este problema, se deben realizar los siguientes pasos:
- Desactive CA1062 en Code Analysis para deshacerse de la advertencia de Code Analysis. Actualmente no hay manera de hacer que el Análisis de Código entienda el
Contract.Requires
.Contract.Requires
. - Habilite "Realizar la verificación estática de contratos" en el panel Contratos de código del proyecto.
- Habilitar "Obligaciones no nulas implícitas"
- Establecer el nivel de advertencia en "hola" (importante, ¡eso era lo que me estaba perdiendo!)
El paso 1 elimina la advertencia de CA, los pasos 2 a 4 habilitan una advertencia de Contratos de Código que es al menos equivalente.