新しくリリースされたVisual Studio 2017 Enterprise(RC)をインストールしました。ただし、Microsoft CodeContractsで動作させるのに問題があります。 VS2015でCodeContractを使用しても問題ありません。何か不足していますか?
この記事の執筆時点では、VS2017の契約定義はありませんが、 NugetパッケージDotNet.Contracts を使用すると、次の方法で回避できます。
DotNet.Contracts.1.10.20606.1\MsBuild
)v14.0
フォルダーをコピーしますv15.0
に変更しますすべてが期待どおりに構築されます。
現在、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に切り替える必要があります。
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>
いくつかのプロジェクトがある場合は、これらをプライベートのヌゲットパッケージに入れ、各プロジェクトでそのヌゲットパッケージを参照することをお勧めします。コードコントラクトの設定(ステップ2から)はmycompany.codecontracts.propsファイルに入れ、コードコントラクトのターゲット(ステップ1から)はmycompany.codecontracts.targetsファイルに入れます。
Nubuildパッケージでのmsbuildプロパティ/ターゲットのパッケージ化の詳細については、こちらをご覧ください: https://docs.Microsoft.com/en-us/nuget/create-packages/creating-a-package#include -msbuild-props-and-targets-in-a-package
十分な関心がある場合は、GitHubで例を提供します。
ここで提案されているアプローチは単純ではなく、特に各開発者のマシンとビルドサーバーの変更が必要になるということがわかりました。
呼び出し元クラスでusing
宣言のグローバル置換のみを必要とするContract.Requires()
の独自の非常に簡略化されたバージョンを作成することにしました。
using MYCommon.Diagnostics; //System.Diagnostics.Contracts;
System.Diagnostics.Contracts
VS 2017で利用可能 および.NetStandardの場合/ ifの場合、適切なバージョンに簡単に戻すことができます。
実際のクラスは次のとおりです。
/// <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");