使用string.IsNullOrWhiteSpace时如何处理Code Contracts警告CC1036?

时间:2016-01-05 13:01:14

标签: c# code-contracts .net-4.6

我有以下代码合同:

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]属性?

5 个答案:

答案 0 :(得分:8)

这里有两点:

<强> 1。为什么[Pure]函数的字符串类中缺少IsNullorWhiteSpace属性?

<强> 2。如何解决CC1030警告问题?

我会尝试讨论两者。

  

<强> 1。为什么缺少[Pure]属性?它没有丢失,元数据似乎没有显示出来。

在以前版本的.NET FX中,这可能不会被标记为Pure,因为他们说:

  

是的,我们需要让我们的检查器对禁用pragma敏感 ......

叹息。

  

我们目前没有实施,但我已将其添加到我们的   工作清单。

请参阅5岁的讨论here

但是在最新的FX(4.6.1)中已将其标记为Pure,请参阅 .NET Framework 4.6.1 ,新的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;
}

那么为什么选择CC1036?

此警告“CC1036”来自CodeContracts ,开发人员昨天只打开此问题(refer here)。

现在,为什么元数据不会随附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并在合同条件下调用此方法。

答案 1 :(得分:7)

通过纯委托将使警告消失。 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 :(得分:5)

虽然有点难看,但您可以使用扩展方法包装函数string.IsNullOrWhiteSpace,并将此新函数标记为Pure

答案 3 :(得分:3)

我刚刚遇到了完全相同的问题。我正在使用VS2015,所以它似乎与VS版本无关。我还在.NET 4.0,4.5.1和4.6上测试了完全相同的代码,但未收到警告。

正如其他人在我之前评论的the IsNullOrWhiteSpace is marked as [Pure] in .NET 4.6.1,并且默认情况下应该被代码契约视为纯粹的,因为它位于System.String命名空间中。这使它看起来像一个bug,所以我提交了an issue to Code Contracts about this,所以运气好的话我们很快就能看到正式答案。

在我们等待答案的同时,有可能(如@Jaco建议的那样)将其包装在扩展方法中并自己标记为Pure。 (可选)您可以取消对该特定方法的警告,如下所示:

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

...但请注意,这也会在同一方法中禁止来自其他合约定义的此警告。

答案 4 :(得分:3)

实际上,这是.NET 4.6+编译方式的问题。请参阅此GitHub pull request

我能够通过修改以下文件来解决这个问题:

  • 对于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拉取请求),我不再收到使用String.IsNullOrWhiteSpace的代码合同静态分析警告。

应该注意的是,引用的pull请求已合并到GitHub上的Code Contracts的主代码中;他们还没有发布包含这些变化的新版本。

此外,对于那些担心更改系统文件的人来说,不是。当下一版本的Code Contracts发布时,它将安装这些文件的更新版本 - 并且希望包含这些更改,并且所有这些都将适用于全世界。 (当然,除非包含更改 - 在这种情况下,您将回到此处参考此帖子以再次进行更改;)lol。)