[英].Net 3.5 Implementation of String.IsNullOrWhitespace with Code Contracts
[英]How to deal with Code Contracts warning CC1036 when using 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]
屬性?
這里我們有兩點:
1.為什么IsNullorWhiteSpace
函數的字符串類中缺少[Pure]
屬性?
2.如何解決CC1030警告問題?
我會嘗試討論兩者。
1.為什么缺少
[Pure]
屬性? 它並沒有丟失,元數據似乎沒有顯示出來。
這可能不會在以前版本的.NET FX中標記為Pure
,因為他們說:
是的, 我們需要讓我們的檢查器對禁用pragma敏感 ...
嘆。
我們目前沒有實現,但我已將其添加到我們的工作列表中。
請參閱這里 5歲的討論。
但是在最新的FX(4.6.1)中已將其標記為Pure
,請參閱.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
並在合同條件中調用它。
通過一個純粹的代表將使警告消失。 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();
}
雖然string.IsNullOrWhiteSpace
丑陋,但你可以用擴展方法包裝函數string.IsNullOrWhiteSpace
並將這個新函數標記為Pure
。
我剛剛遇到了完全相同的問題。 我正在使用VS2015,所以它似乎與VS版本無關。 我還在.NET 4.0,4.5.1和4.6上測試了完全相同的代碼,但未收到警告。
像其他人在我之前評論過的那樣, IsNullOrWhiteSpace
在.NET 4.6.1中被標記為[Pure]
,並且默認情況下應該被Code Contracts認為是純的,因為它位於System.String
命名空間中。 這使它看起來像一個bug,所以我已經向Code Contracts提交了一個關於這個的問題 ,所以運氣好的話我們很快就會看到一個正式答案。
當我們等待答案時,有可能(如@Jaco建議的那樣)將其包裝在擴展方法中並將其標記為Pure
。 (可選)您可以禁止該特定方法的警告,如下所示:
[SuppressMessage("Microsoft.Contracts", "CC1036", Justification = "string.IsNullOrWhiteSpace is Pure")]
...但請注意,這也會在同一方法中禁止來自其他合同定義的此警告。
實際上,這是.NET 4.6+編譯方式的問題。 請參閱此GitHub拉取請求 。
我能夠通過修改以下文件來解決這個問題:
C:\\Program Files (x86)\\Microsoft\\Contracts\\MsBuild\\v12.0\\Microsoft.CodeContracts.Targets
C:\\Progarm Files (x86)\\Microsoft\\Contracts\\MsBuild\\v14.0\\Microsoft.CodeContracts.Targets
在這兩個文件中,確保第一個<Choose>
元素的<Otherwise>
子元素具有以下內容:
...
<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請求),我不再收到使用String.IsNullOrWhiteSpace
Code Contracts靜態分析警告。
應該注意的是,引用的pull請求已經合並到GitHub上的Code Contracts的主代碼中; 他們還沒有發布包含這些更改的新版本。
此外,對於那些擔心更改“系統文件”的人,請不要這樣做。 當下一版本的Code Contracts發布時,它將安裝這些文件的更新版本 - 並且希望包含這些更改,並且所有這些都將適用於全世界。 (當然,除非更改未包括在內 - 在這種情況下,您將回到此處參考此帖子以再次進行更改;)大聲笑。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.