VS2017可以与CodeContracts一起使用吗?

时间:2016-11-23 15:08:29

标签: code-contracts visual-studio-2017

我刚安装了新发布的Visual Studio 2017 Enterprise(RC)。但是我无法使用Microsoft CodeContracts。我对使用VS2015的CodeContract没有任何问题。我错过了什么吗?

5 个答案:

答案 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,您可以使用以下内容解决此问题:

  • 导航到CodeContracts nuget包目录(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产品名称,例如:社区。

这将允许您使用VS2017中的代码合同进行构建,但无法解决“项目设置”中未显示的CC选项卡问题。为此,您仍然需要切换到VS2015。

答案 3 :(得分:5)

代码合同在VS 2017中不起作用的原因是:

  1. 代码合同MSBuild文件未导入到msbuild文件的VS 2017树中(易于修复)
  2. VS 2017项目属性中不存在代码合同配置UI(通过包含CodeContracts msbuild属性轻松修复)
  3. 当然,有关CodeContracts未来的问题是有效的,但您可以实施以下内容以启用使用CodeContracts在VS 2017中构建的现有项目:

    1. 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" />
      
    2. 请注意,如果安装了CodeContracts,则不需要第一个PropertyGroup,应将b / c CodeContractsInstallDir指定为环境变量。在这种情况下,您只需添加

      就可以逃脱
      <Import Condition="'$(CodeContractsImported)' != 'true' AND '$(DontImportCodeContracts)' != 'true'" Project="$(CodeContractsInstallDir)MsBuild\v$(VisualStudioVersion)\Microsoft.CodeContracts.targets" />
      

      到* .csproj文件。

      1. 在* .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>
        
      2. 如果您有多个项目,我建议将这些项目放在私有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");