c# code-contracts .net-4.6

c# - ¿Cómo lidiar con los contratos de código de advertencia de CC1036 cuando se utiliza string.IsNullOrWhiteSpace?



code-contracts .net-4.6 (5)

Acabo de encontrar el mismo problema. Estoy usando VS2015, por lo que no parece estar relacionado con la versión VS. También probé exactamente el mismo código en .NET 4.0, 4.5.1 y 4.6, sin recibir la advertencia.

Como otros han comentado antes que yo, IsNullOrWhiteSpace está marcado como [Pure] en .NET 4.6.1 y, además, por defecto, los Contratos de Código deben considerar que está puro porque está en el espacio de nombres System.String . Esto hace que parezca un error, por lo que he enviado un problema a los contratos de código al respecto , por lo que con un poco de suerte pronto veremos una respuesta oficial.

Mientras esperamos una respuesta, es posible (como sugiere @Jaco) envolverlo en un método de extensión y marcarlo como Pure usted mismo. Opcionalmente, puede suprimir la advertencia para ese método en particular como este:

[SuppressMessage("Microsoft.Contracts", "CC1036", Justification = "string.IsNullOrWhiteSpace is Pure")]

... pero tenga en cuenta que esto también suprimirá esta advertencia de otras definiciones de contrato en el mismo método.

Tengo el siguiente contrato de código:

public void F(string x) { Contract.Requires(!string.IsNullOrWhiteSpace(x)); throw new NotImplementedException(); }

Al compilar, me sale la siguiente advertencia:

advertencia CC1036: Llamada detectada al método ''System.String.IsNullOrWhiteSpace (System.String)'' sin [Pure] en los contratos del método [...]

¿Como lidiar con?

Lo que es extraño, es que también estoy usando string.IsNullOrEmpty , que no está marcado como [Pure] también, en otros contratos y el reescritor no tiene ningún problema con eso.

La versión de mi contrato de reescritura es 1.9.10714.2.

Esta es la parte relevante de la implementación de String clase String que estoy usando (recuperada de metadatos):

#region Assembly mscorlib.dll, v4.0.0.0 // C:/Program Files (x86)/Reference Assemblies/Microsoft/Framework/.NETFramework/v4.6.1/mscorlib.dll #endregion using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security; using System.Text; namespace System { // Summary: // Represents text as a series of Unicode characters.To browse the .NET Framework // source code for this type, see the Reference Source. [Serializable] [ComVisible(true)] public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable, IComparable<string>, IEnumerable<char>, IEquatable<string> { // [...] // // Summary: // [...] public static bool IsNullOrEmpty(string value); // // Summary: // [...] public static bool IsNullOrWhiteSpace(string value);

¿Por qué falta el atributo [Pure] ?


Aquí tenemos dos puntos:

1. ¿Por qué falta el atributo [Pure] en la clase de cadena para la función IsNullorWhiteSpace ?

2. ¿Cómo resolver el problema de advertencia CC1030?

Intentaré discutir ambos.

1. ¿Por qué falta el atributo [Pure] ? No falta, los metadatos no parecen estar mostrando esto.

Esto puede no estar marcado como Pure en la versión anterior de .NET FX, como decían:

Sí, tenemos que hacer que nuestro verificador sea sensible al pragma inhabilitado ...

Suspiro.

Actualmente no tenemos eso implementado, pero lo he agregado a nuestra lista de trabajo.

Consulte la discusión de 5 años here .

Pero esto se ha marcado como Pure en el último FX (4.6.1). Consulte .NET Framework 4.6.1 , el nuevo código de clase de string .

[Pure] public static bool IsNullOrWhiteSpace(String value) { if (value == null) return true; for(int i = 0; i < value.Length; i++) { if(!Char.IsWhiteSpace(value[i])) return false; } return true; }

Entonces, ¿por qué CC1036?

Esta advertencia "CC1036" proviene de CodeContracts , los desarrolladores han abierto este problema solo ayer ( consulte aquí ).

Ahora, por qué los metadatos no escupen los atributos de Pure , esta es una pregunta diferente, como para el método Equals , se agrega Pure pero solo se muestra SecuritySafeCritical en el código de metadatos.

[SecuritySafeCritical] public static bool Equals(String a, String b, StringComparison comparisonType);

El mismo problema se aplica a Invariant() . Dado el siguiente código, se muestran las mismas advertencias:

private string testString = "test"; [ContractInvariantMethod] private void TestInvariant() { Contract.Invariant(!string.IsNullOrWhiteSpace(testString)); }

¿Cómo resolver?

Como otros también sugieren, cree otro método, márquelo como Pure y llámelo en su condición de contrato.


Aunque un poco feo, puede envolver la string.IsNullOrWhiteSpace con un método de extensión y marcar esta nueva función como Pure .


En realidad, este es un problema con la forma en que se compila .NET 4.6+. Ver esta solicitud de extracción GitHub .

Pude solucionar este problema modificando los siguientes archivos:

  • Para Visual Studio 2013:
    • C:/Program Files (x86)/Microsoft/Contracts/MsBuild/v12.0/Microsoft.CodeContracts.Targets
  • Para Visual Studio 2015:
    • C:/Progarm Files (x86)/Microsoft/Contracts/MsBuild/v14.0/Microsoft.CodeContracts.Targets

En ambos archivos, asegúrese de que el elemento secundario <Otherwise> del primer elemento <Choose> tenga el siguiente contenido que se muestra a continuación:

... <Choose> <When Condition="''$(TargetFrameworkIdentifier)'' == ''Silverlight''"> ... </When> <Otherwise> <Choose> <When Condition="''$(TargetFrameworkVersion)'' == ''v4.0"> <PropertyGroup> <CodeContractsReferenceAssemblyLibPath>$(CodeContractsInstallDir)Contracts/.NETFramework/v4.0</CodeContractsReferenceAssemblyLibPath> </PropertyGroup> </When> <When Condition="''$(TargetFrameworkVersion)'' == ''v4.5''"> <PropertyGroup> <CodeContractsReferenceAssemblyLibPath>$(CodeContractsInstallDir)Contracts/.NETFramework/v4.5</CodeContractsReferenceAssemblyLibPath> </PropertyGroup> </When> <When Condition="''$(TargetFrameworkVersion)'' == ''v4.5.1''"> <PropertyGroup> <CodeContractsReferenceAssemblyLibPath>$(CodeContractsInstallDir)Contracts/.NETFramework/v4.5</CodeContractsReferenceAssemblyLibPath> </PropertyGroup> </When> <When Condition="''$(TargetFrameworkVersion)'' == ''v4.5.2''"> <PropertyGroup> <CodeContractsReferenceAssemblyLibPath>$(CodeContractsInstallDir)Contracts/.NETFramework/v4.5</CodeContractsReferenceAssemblyLibPath> </PropertyGroup> </When> <When Condition="''$(TargetFrameworkVersion)'' == ''v4.6''"> <PropertyGroup> <CodeContractsReferenceAssemblyLibPath>$(CodeContractsInstallDir)Contracts/.NETFramework/v4.5</CodeContractsReferenceAssemblyLibPath> </PropertyGroup> </When> <When Condition="''$(TargetFrameworkVersion)'' == ''v4.6.1''"> <PropertyGroup> <CodeContractsReferenceAssemblyLibPath>$(CodeContractsInstallDir)Contracts/.NETFramework/v4.5</CodeContractsReferenceAssemblyLibPath> </PropertyGroup> </When> <Otherwise> <PropertyGroup> <CodeContractsReferenceAssemblyLibPath>$(CodeContractsInstallDir)Contracts/.NETFramework/v3.5</CodeContractsReferenceAssemblyLibPath> </PropertyGroup> </Otherwise> </Choose> </Otherwise> </Chose> ...

Después de realizar estos cambios en estos archivos (según la solicitud de extracción de GitHub mencionada anteriormente), ya no recibí advertencias de análisis estático de Contratos de Código para el uso de String.IsNullOrWhiteSpace .

Se debe tener en cuenta que la solicitud de extracción a la que se hace referencia se ha fusionado con el código principal de los Contratos de Código en GitHub; simplemente no han hecho una nueva versión que contenga estos cambios todavía.

Además, para aquellos preocupados por cambiar "archivos de sistema", no lo sea. Cuando se lance la próxima versión de Code Contracts, se instalarán versiones actualizadas de estos archivos y, con suerte, se incluirán los cambios y todo estará bien con el mundo. (A menos que, por supuesto, los cambios no se incluyan, en cuyo caso, volverá aquí para hacer referencia a esta publicación para volver a hacer esos cambios).


Pasar por un delegado puro hará que la advertencia desaparezca. Predicate<T> ya está marcado como puro, así que puedes usarlo para solucionar el error:

// Workaround for https://github.com/Microsoft/CodeContracts/issues/339 public Predicate<string> IsNullOrWhiteSpace = string.IsNullOrWhiteSpace; public void F(string x) { Contract.Requires(!IsNullOrWhiteSpace(x)); throw new NotImplementedException(); }