我刚安装了新发布的Visual Studio 2017 Enterprise(RC)。但是我无法使用Microsoft CodeContracts。我对使用VS2015的CodeContract没有任何问题。我错过了什么吗?
答案 0 :(得分:21)
正如其他人所指出的那样,Microsoft没有优先考虑代码合同及其long-term support remains unclear(尽管 已经通过Roslyn <{3}}了。)
从ongoing discussion about language-level integration开始,社区投稿人March 11th, 2017至少更新了Yaakov以包含source code(谢谢!)。此版本支持编译期间的静态检查以及使用CCRewrite
的运行时验证。
注意:此版本不通过Visual Studio 2017 build targets提供配置支持。因此,需要通过手动将适当的属性添加到
csproj
文件来配置代码协定。请参阅@ crimbo在上面的答案project's properties pane。
不幸的是,虽然这些更新已合并到主代码分支中,但它们既没有反映在comprehensive list of properties或官方Marketplace distribution中。因此,您需要从存储库下载并编译NuGet Package(这很简单;只需使用提供的BuildCC.bat
文件)。
重要:代码约定的静态分析具有对.NET 3.5的硬编码依赖性,默认情况下不再在Windows 10或Visual Studio 2017中安装。因此,您&# 39;我想确保这个&#34;功能&#34;已启用(或source code);否则,您将收到编译时错误。
或者,从download it separately开始,June 15th, 2017已在其Igor Bek中包含此更新,因此最简单的方法是简单地添加CodeContracts.MSBuild&#39;到packages.config
通过:
Install-Package CodeContracts.MSBuild -Version 1.9.10714.3
背景:NuGet Package首先将此包放在一起作为Igor Bek,后来成为proof-of-concept for the Code Contracts team的基础(在v1.10.10126.2中) )。由于微软尚未更新官方NuGet包,因此他现在是最新的。
鉴于当前的支持状态,我不鼓励人们为新项目采用代码合同,但这应该为已经投资到现有.NET Framework项目的代码合同的开发人员提供向后兼容性。
答案 1 :(得分:13)
在撰写本文时,VS2017没有合约定义,但如果使用Nuget package DotNet.Contracts,您可以使用以下内容解决此问题:
DotNet.Contracts.1.10.20606.1\MsBuild
)v14.0
文件夹v15.0
一切都应按预期建立。
答案 2 :(得分:7)
目前没有支持Visual Studio 2017的Code Contracts for .NET版本。但是,如果您复制以下目标文件,则可以解决该问题
C:\Program Files (x86)\MSBuild\4.0\Microsoft.Common.Targets\ImportAfter\CodeContractsAfter.targets
到VS2017 MSBuild的ImportAfter位置:
C:\Program Files (x86)\Microsoft Visual Studio\2017\#YourVS2017Product#\MSBuild\15.0\Microsoft.Common.targets\ImportAfter
注意:将#YourVS2017Product#替换为上述路径中的VS2017产品名称,例如:社区。 P>
这将允许您使用VS2017中的代码合同进行构建,但无法解决“项目设置”中未显示的CC选项卡问题。为此,您仍然需要切换到VS2015。
答案 3 :(得分:5)
代码合同在VS 2017中不起作用的原因是:
当然,有关CodeContracts未来的问题是有效的,但您可以实施以下内容以启用使用CodeContracts在VS 2017中构建的现有项目:
将C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.Targets\ImportAfter\CodeContractsAfter.targets
的内容添加到csproj文件中(直接或间接通过导入)。最基本的方法是将其添加到csproj文件中:
<PropertyGroup>
<CodeContractsInstallDir Condition="'$(CodeContractsInstallDir)'==''">C:\Program Files (x86)\Microsoft\Contracts\</CodeContractsInstallDir>
</PropertyGroup>
<Import Condition="'$(CodeContractsImported)' != 'true' AND '$(DontImportCodeContracts)' != 'true'" Project="$(CodeContractsInstallDir)MsBuild\v$(VisualStudioVersion)\Microsoft.CodeContracts.targets" />
请注意,如果安装了CodeContracts,则不需要第一个PropertyGroup,应将b / c CodeContractsInstallDir
指定为环境变量。在这种情况下,您只需添加
<Import Condition="'$(CodeContractsImported)' != 'true' AND '$(DontImportCodeContracts)' != 'true'" Project="$(CodeContractsInstallDir)MsBuild\v$(VisualStudioVersion)\Microsoft.CodeContracts.targets" />
到* .csproj文件。
在* .csproj文件中指定所有CodeContracts属性(直接或间接通过导入)。例如:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Code Contracts settings -->
<PropertyGroup>
<CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
<CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>False</CodeContractsEnumObligations>
<CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
<CodeContractsInferRequires>False</CodeContractsInferRequires>
<CodeContractsInferEnsures>False</CodeContractsInferEnsures>
<CodeContractsInferObjectInvariants>False</CodeContractsInferObjectInvariants>
<CodeContractsSuggestAssumptions>False</CodeContractsSuggestAssumptions>
<CodeContractsSuggestRequires>True</CodeContractsSuggestRequires>
<CodeContractsSuggestEnsures>False</CodeContractsSuggestEnsures>
<CodeContractsSuggestObjectInvariants>False</CodeContractsSuggestObjectInvariants>
<CodeContractsDisjunctiveRequires>False</CodeContractsDisjunctiveRequires>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
<CodeContractsCacheAnalysisResults>True</CodeContractsCacheAnalysisResults>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<CodeContractsRuntimeCheckingLevel>ReleaseRequires</CodeContractsRuntimeCheckingLevel>
</PropertyGroup>
</Project>
如果您有多个项目,我建议将这些项目放在私有nuget包中,并在每个项目中引用该nuget包。代码契约设置(从步骤2开始)可以放在mycompany.codecontracts.props文件中,代码契约目标(从步骤1开始)可以放在mycompany.codecontracts.targets文件中。
有关在nuget包中打包msbuild属性/目标的更多信息:https://docs.microsoft.com/en-us/nuget/create-packages/creating-a-package#including-msbuild-props-and-targets-in-a-package
如果有足够的兴趣,我愿意在GitHub上提供一个例子。
答案 4 :(得分:1)
我发现这里建议的方法并不简单,特别是它需要在每个开发人员的计算机和构建服务器上进行更改。
我决定创建自己的非常简化的版本的Contract.Requires()
,它只需要在调用者类中全局替换using
声明。
using MYCommon.Diagnostics; //System.Diagnostics.Contracts;
当/ System.Diagnostics.Contracts
will be available for VS 2017和.NetStandard时,很容易恢复到正确的版本。
实际的课程是:
/// <summary>
/// Contract.Requires(config != null); in VS 2017 not throw ArgumentNullException
/// The class is workaround for https://stackoverflow.com/questions/40767941/does-vs2017-work-with-codecontracts
/// </summary>
public class Contract
{
public static void Requires(bool condition, string message = null)
{
Requires<ArgumentNullException>(condition, message);
}
public static void Requires<TException>(bool condition, string message=null) where TException:Exception , new ()
{
if (!condition)
{
//https://stackoverflow.com/questions/41397/asking-a-generic-method-to-throw-specific-exception-type-on-fail/41450#41450
var e=default(TException);
try
{
message = message ?? "Unexpected Condition"; //TODO consider to pass condition as lambda expression
e = Activator.CreateInstance(typeof(TException), message) as TException;
}
catch (MissingMethodException ex)
{
e = new TException();
}
throw e;
}
}
}
基本限制是典型的使用Contract.Requires(param1!=null);
不允许我使用参数名称抛出异常,并且更好的使用时间会更长:
Contract.Requires<ArgumentNullException>(param1!=null, "param1 is null");