Cómo lidiar con Contratos de código advirtiendo CC1036 cuando se usa string.¿Es el espacio blanco Cero?


Tengo el siguiente código de contrato:

public void F(string x)
{
    Contract.Requires(!string.IsNullOrWhiteSpace(x));

    throw new NotImplementedException();
}

Al compilar, recibo la siguiente advertencia:

Advertencia CC1036: Llamada detectada al sistema del método.Cadena.IsNullOrWhiteSpace (System.String) ' sin [Puro] en contratos de método [...]

¿Cómo lidiar con eso?

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 un problema con eso.

Mi Contrato de Reescritura La versión es 1.9.10714.2.

Esta es la parte relevante de la implementación de String la clase que estoy usando (recuperada de los 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]?

Author: leppie, 2016-01-05

5 answers

Pasar por un delegado puro hará que la advertencia desaparezca. Predicate<T> ya está marcado como puro, por lo que puede usarlo para evitar 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();
}
 7
Author: Mark Waterman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-21 18:48:51

Aquí tenemos dos puntos:

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

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

Trataré de 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, estaban diciendo:

Sí, necesitamos hacer que nuestro comprobador sea sensible al pragma de desactivación...

[15] Suspiro.

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

Refiérase a la discusión de 5 años aquí.

Pero esto ha sido marcado como Pure en la última FX (4.6.1), Consulte . NET Framework 4.6.1 , el nuevo string class code .

[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" es de CodeContracts , los desarrolladores han abierto este problema solo ayer ( consulte aquí).

Ahora, por qué los metadatos no escupen atributos 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, el las mismas advertencias son muestra:

private string testString = "test";

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

Cómo resolver?

Como otros también están sugiriendo, cree otro método, márquelo como Pure y llame a esto en su condición de contrato.

 8
Author: Anil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-22 20:19:01

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

 5
Author: Jaco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-22 20:24:03

Acabo de encontrar exactamente 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, el IsNullOrWhiteSpace está marcado como [Pure] en.NET 4.6.1, y además debe considerarse puro por defecto por Contratos de Código porque está en el espacio de nombres System.String. Esto hace que parezca un error, por lo que he enviado un problema al Código Contratos sobre esto, así que con un poco de suerte veremos una respuesta oficial pronto.

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 de la siguiente manera:

[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.

 3
Author: Desarc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-23 19:42:54

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

Pude solucionar esto 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 hacer estos cambios en estos archivos (según la solicitud de extracción de GitHub mencionada anteriormente), ya no recibí avisos de análisis estático de Contratos de código para el uso de String.IsNullOrWhiteSpace.

Debe tenerse en cuenta que la solicitud de extracción referenciada se ha fusionado en el código principal para los Contratos de Código en GitHub; simplemente no han hecho una nueva versión que contenga estos cambios todavía.

También, para aquellos preocupados por cambiar los "archivos del sistema", no lo estén. Cuando se publique la próxima versión de Contratos de código, instale versiones actualizadas de estos archivos hopefully y esperemos que los cambios se incluirán, y todo estará bien con el mundo. (A menos, por supuesto, que los cambios no estén incluidos--en cuyo caso, volverás aquí para hacer referencia a este post para hacer esos cambios de nuevo ;) lol.)

 3
Author: fourpastmidnight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-20 05:14:57