Я только что установил недавно выпущенную Visual Studio 2017 Enterprise (RC). У меня возникли проблемы с его работой с Однако кодовые контракты. У меня нет проблем с использованием Code Contracts в Visual Studio 2015. Я что-то упустил?
Работает ли Visual Studio 2017 с кодовыми контрактами?
Ответы (5)
Как уже отмечалось, Microsoft не уделяла приоритетное внимание Code Contracts, и ее долгосрочная поддержка остается неясной (хотя была некоторая текущая дискуссия об интеграции на уровне языка через Рослин).
Однако по состоянию на 11 марта 2017 г. участник сообщества Яаков как минимум обновил исходный код для включения целей сборки Visual Studio 2017 ( Спасибо!). Эта версия поддерживает как статическую проверку во время компиляции, так и проверку во время выполнения с использованием CCRewrite
.
Примечание. Эта сборка не поддерживает настройку через панель свойств проекта. Таким образом, контракты кода необходимо настроить, вручную добавив соответствующие свойства в файл
csproj
. полный список свойств см. в ответе @crimbo ниже.
К сожалению, хотя эти обновления были объединены в ветку основного кода, они не отражены в Marketplace. дистрибутив или официальный пакет NuGet. Таким образом, вам необходимо загрузить и скомпилировать исходный код из репозитория (что несложно; просто используйте прилагаемый файл BuildCC.bat
).
Важно. Статический анализ Code Contracts имеет жестко запрограммированную зависимость от .NET 3.5, которая больше не устанавливается по умолчанию ни в Windows 10, > или Visual Studio 2017. Таким образом, вы должны убедиться, что эта «функция» включена (или скачать отдельно); в противном случае вы получите ошибку времени компиляции.
Кроме того, по состоянию на 15 июня 2017 г., а затем обновлено 6 февраля, 2018 г. — участник Игорь Бек включил это обновление в свой Пакет NuGet, поэтому проще всего просто добавить CodeContracts.MSBuild
к packages.config
через:
Install-Package CodeContracts.MSBuild -Version 1.12.0
Предыстория: Игорь Бек сначала собрал этот пакет в виде проверка концепции для команды Code Contracts, а позже она стала основой для официальный пакет NuGet (в версии 1.10.10126.2). Поскольку Microsoft не обновляла официальный пакет NuGet, теперь он является самым последним.
Учитывая текущее состояние поддержки, я бы не рекомендовал людям использовать Code Contracts для новых проектов, но это должно обеспечить обратную совместимость для разработчиков, которые уже вложили средства в Code Contracts для существующих проектов .NET Framework.
На данный момент для VS2017 нет определений контрактов, но вы можете обойти это с помощью следующего, если используете Пакет Nuget DotNet.Contracts:
- Перейдите в каталог пакетов CodeContracts nuget (
DotNet.Contracts.1.10.20606.1\MsBuild
). - Скопируйте папку
v14.0
- Переименуйте его в
v15.0
Все должно построиться так, как ожидалось.
@JeremyCaney
, я установил пакет NuGet CodeContracts.MSBuild. Это, а также редактирование файла .csproj для указания конфигурации — это все, что вам нужно сделать.
- person Igor; 19.03.2018
В настоящее время нет версии Code Contracts для .NET, поддерживающей Visual Studio 2017. Однако проблему можно решить, если вы скопируете следующий целевой файл
C:\Program Files (x86)\MSBuild\4.0\Microsoft.Common.Targets\ImportAfter\CodeContractsAfter.targets
в расположение ImportAfter вашего VS2017 MSBuild:
C:\Program Files (x86)\Microsoft Visual Studio\2017\#YourVS2017Product#\MSBuild\15.0\Microsoft.Common.targets\ImportAfter
Примечание. Замените #YourVS2017Product# названием вашего продукта VS2017 в указанном выше пути, например. Сообщество.
Это позволит вам создавать с помощью Code Contracts в VS2017, но не решит проблему, когда вкладка CC не отображается в настройках проекта. Для этого вам все равно нужно переключиться на VS2015.
Ensures()
в конце члена).
- person Jeremy Caney; 24.09.2017
Причины, по которым контракты кода не работают в VS 2017:
- Контракты кода Файлы MSBuild не импортируются в дерево файлов msbuild VS 2017 (легко исправить)
- Пользовательский интерфейс конфигурации контрактов кода отсутствует в свойствах проекта VS 2017 (это легко исправить, включив свойства CodeContracts msbuild)
Конечно, вопросы о будущем 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" />
Обратите внимание, что первая PropertyGroup не нужна, если установлен CodeContracts, b/c CodeContractsInstallDir
следует указать в качестве переменной среды. В этом случае вы можете уйти, просто добавив
<Import Condition="'$(CodeContractsImported)' != 'true' AND '$(DontImportCodeContracts)' != 'true'" Project="$(CodeContractsInstallDir)MsBuild\v$(VisualStudioVersion)\Microsoft.CodeContracts.targets" />
в ваши файлы *.csproj.
Укажите все свойства CodeContracts в файле *.csproj (напрямую или косвенно через Import). Например:
<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.
Дополнительные сведения об упаковке свойств/целей msbuild в пакет nuget можно найти здесь: https://docs.microsoft.com/en-us/nuget/create-packages/creating-a-package#Include-msbuild-props-и-цели-в-пакете
Я готов предоставить пример на GitHub, если будет достаточный интерес.
csproj
.
- person Jeremy Caney; 25.09.2017
csproj
. Но они определенно необходимы, чтобы в противном случае включить как статическую проверку, так и проверку во время выполнения.
- person Jeremy Caney; 28.09.2017
Я обнаружил, что предложенные здесь подходы не были простыми, в частности, это потребовало бы изменений на машинах каждого разработчика, а также на сервере сборки.
Я решил создать свою собственную очень упрощенную версию Contract.Requires()
, которая потребует только глобальной замены объявления using
в вызывающих классах.
using MYCommon.Diagnostics; //System.Diagnostics.Contracts;
Когда/если System.Diagnostics.Contracts
будет доступен для 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");
Requires()
во время выполнения. И его можно расширить для поддержки Assert()
, Assume()
, Exists()
и ForAll()
без особых усилий. Однако, если они потребуются, будет непрактично (без серьезного рефакторинга вызывающих) поддерживать Ensures()
, Invariant()
, Result()
или ValueAtReturn()
, используя этот подход. Другими словами, это действительно работает только как сокращение для проверки предварительных условий.
- person Jeremy Caney; 24.09.2017
Ensure
делает этот вопрос спорным. С другой стороны, белый Require
легко, Ensure
чрезвычайно сложен.
- person Wiktor Zychla; 03.06.2020