Подтвердить что ты не робот

Как бороться с предупреждением Code Contracts CC1036 при использовании string.IsNullOrWhiteSpace?

У меня есть следующий код:

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

    throw new NotImplementedException();
}

При компиляции я получаю следующее предупреждение:

предупреждение CC1036: обнаруженный вызов метода 'System.String.IsNullOrWhiteSpace(System.String)' без [Pure] в контрактах метода [...]

Как с этим бороться?

Что странно, я также использую string.IsNullOrEmpty, который не помечен как [Pure], а также в других контрактах, и у переписывающего устройства нет проблем с этим.

Моя версия для перезапуска моего контракта - 1.9.10714.2.

Это важная часть из реализации класса String, который я использую (из метаданных):

#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);

Почему атрибут [Pure] отсутствует?

4b9b3361

Ответ 1

Прохождение чистого делегата заставит предупреждение уйти. Predicate<T> уже отмечен как чистый, поэтому вы можете просто использовать это, чтобы обойти ошибку:

// 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();
}

Ответ 2

Здесь мы имеем две точки:

1. Почему атрибут [Pure] отсутствует в строковом классе для функции IsNullorWhiteSpace?

2. Как устранить проблему с предупреждением CC1030?

Я попытаюсь обсудить оба.

1. Почему атрибут [Pure] отсутствует?. Его не хватает, метаданные, похоже, не показывают этого.

Это не может быть помечено как Pure в предыдущей версии .NET FX, поскольку они говорили:

Да, нам нужно сделать нашу проверку чувствительной к отключенной прагме...

Вздох.

В настоящее время у нас нет этого, но я добавил его к нашей рабочий список.

Обратитесь к 5-летнему обсуждению здесь.

Но это было отмечено как Pure в последнем FX (4.6.1), см. .NET Framework 4.6.1, новый 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;
}

Тогда почему CC1036?

Это предупреждение "CC1036" происходит от CodeContracts, разработчики открыли эту проблему только вчера (см. здесь).

Теперь, почему метаданные не плюют на атрибуты Pure, это другой вопрос, например, для метода Equals, добавлен Pure, но только код SecuritySafeCritical отображается в метаданных.

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

То же самое относится к Invariant(). Учитывая следующий код, отображаются те же предупреждения:

private string testString = "test";

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

Как разрешить?

Как и другие предложения, создайте другой метод, пометьте его как Pure и вызовите это в условиях контракта.

Ответ 3

Как бы уродливо, вы можете обернуть функцию string.IsNullOrWhiteSpace с помощью метода расширения и пометить эту новую функцию как Pure.

Ответ 4

Я столкнулся с одной и той же проблемой. Я использую VS2015, поэтому он, похоже, не связан с версией VS. Я также тестировал один и тот же код на .NET 4.0, 4.5.1 и 4.6, не получая предупреждения.

Как и другие комментировали передо мной, IsNullOrWhiteSpace помечен как [Pure] в .NET 4.6.1, а также должен по умолчанию считаются чистыми по кодовым контрактам, поскольку они находятся в пространстве имен System.String. Это делает его похожим на ошибку, поэтому я представил проблему с кодовыми контрактами об этом, поэтому с некоторой удачей мы скоро увидим официальный ответ.

Пока мы ждем ответа, возможно (например, @Jaco предлагает) обернуть его в метод расширения и пометить его как Pure самостоятельно. При желании вы можете подавить предупреждение для этого конкретного метода следующим образом:

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

... но обратите внимание, что это также подавляет это предупреждение из других определений Контракта тем же методом.

Ответ 5

Собственно, это проблема с тем, как компилируется .NET 4.6+. Смотрите запрос на удаление GitHub.

Мне удалось обойти это, изменив следующие файлы:

  • Для Visual Studio 2013:
    • C:\Program Files (x86)\Microsoft\Contracts\MsBuild\v12.0\Microsoft.CodeContracts.Targets
  • Для Visual Studio 2015:
    • C:\Progarm Files (x86)\Microsoft\Contracts\MsBuild\v14.0\Microsoft.CodeContracts.Targets

В обоих файлах дочерний элемент <Otherwise> первого элемента <Choose> имеет следующее содержимое, показанное ниже:

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

После внесения этих изменений в эти файлы (по запросу GitHub pull, указанному выше), я больше не получал предупреждения статического анализа Code Contracts для использования String.IsNullOrWhiteSpace.

Следует отметить, что ссылка на запрос на тягу была объединена в основной код для кодовых контрактов на GitHub; они просто еще не выпустили новый релиз, содержащий эти изменения.

Кроме того, для тех, кто заинтересован в смене "системных файлов", не стоит. Когда будет выпущена следующая версия Code Contracts, она установит обновленные версии этих файлов - и, надеюсь, изменения будут включены, и все будет правильно с миром. (Если, конечно, изменения не включены - в этом случае вы вернетесь сюда, чтобы ссылаться на это сообщение, чтобы снова внести эти изменения;) lol.)