Код контракта или выражение?

Я просто попытался использовать Контракты кода, и я не вижу реальных преимуществ перед if statement.

Рассмотрим следующее.

private static void BindClassesToInterfacesByConvention(string classesEndingWith
    , string interfacesEndingwith) {
    Contract.Requires<ArgumentNullexception>(
        string.IsNullOrWhiteSpace(classesEndingWith)
        , "classesEndingWith");

    Contract.Requires<ArgumentNullException>(
        string.IsNullOrWhitespace(interfacesEndingWith)
        , "interfacesendingWith");

    ...
}

Я нахожу это более запутанным, чем просто используя if statement

private static void BindClassesToInterfacesByConvention(string classesEndingWith
    , string interfacesEndingwith) {
    if (string.IsNullOrWhiteSpace(classesEndingWith)) 
        throw new ArgumentNullException("classesEndingWith");

    if (string.IsNullOrWhitespace(interfacesEndingWith))
        throw new ArgumentNullException("interfacesendingWith");

    ...
}

Контракты кода должны предупредить меня во время компиляции, что нарушен контракт. Таким образом, я ожидал получить сообщение об ошибке или предупреждение, когда написал следующее.

BindClassesToInterfacesByConvention(null, null);

И ничего не произошло, все составлено просто отлично, и не появилось ни сообщения об ошибке, ни предупреждения.

В этом сценарии я считаю, что лучше продолжить с it statement. Или, возможно, это было несправедливое использование Code Contracts?

Ответ 1

Кодовые контракты - отличная идея, сложенная инструментами, которая не совсем там. Во-первых, для того, чтобы сделать исключения на самом деле, вы должны установить правильные расширения в Visual Studio и/или настроить правильные настройки в своем проекте. Большое удовольствие, если у вас есть модульные тесты, основанные на контрактах кода, которые бросают исключения во время выполнения и запускают их на сервере сборки.

Однако важно понимать, что настоящая цель Кодовых контрактов - это не просто исключение. Он позволяет проводить статический анализ кода (если вы его включаете), который при включении может дать вам сообщение об ошибке во время компиляции, но он требует, чтобы вы выполняли большую работу, чтобы применить его почти везде, для того чтобы статический анализ кода, чтобы действительно работать. Я считаю, что это сценарий, который вы пытаетесь проверить? В этом случае я предлагаю вам посмотреть настройки контрактов кода для вашего проекта, чтобы убедиться, что вы включили проверку статического кода (это сделает вашу сборку довольно длинной).

Кроме того, важно заключить, что кодовые контракты позволяют сообщать намерения вызывающим вашим методам; Intellisense подберет условия, которые вы указали (при условии установки правильных расширений). Информацию о кодовых контрактах можно также автоматически добавить в файл XML, который может сопровождать сборки, что затем позволит сторонним пользователям вашей сборки знать о ваших требованиях при написании кода, а также позволяет включать эту информацию в файлах справки, созданных с помощью Sandcastle и т.д.

Это отличная идея, которая еще не полностью реализована в инструментах, поэтому время от времени вы получаете какое-то смешное поведение. Лично я в значительной степени прекратил использовать их в настоящее время.

Ответ 2

Вы указываете метод, который требует, чтобы его аргументы были пустыми или пустыми, а затем передавали значение null. Договор выполнен. Вот почему у вас не было нарушения контракта. (Requires() требуется выдает исключение, когда условие принимает значение false, а не true).

Кроме того, даже если вы исправите контракт, вы не должны бросать ArgumentNullException, если значение параметра - это непустая строка, не содержащая символов или только пробельные символы. В этом случае вы должны выбросить ArgumentException.

Я бы сделал это:

private static void BindClassesToInterfacesByConvention(string classesEndingWith
    , string interfacesEndingwith) {
    Contract.Requires<ArgumentNullException>(classesEndingWith != null
        , "classesEndingWith");

    Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(classesEndingWith)
        , "classesEndingWith");

    Contract.Requires<ArgumentNullException>(interfacesEndingWith != null
        , "interfacesEndingWith");

    Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(interfacesEndingWith)
        , "interfacesEndingWith");

    ...
}

Чтобы загрузить инструменты анализа контрактов Code Contracts, включая интеграцию Visual Studio, посетите http://visualstudiogallery.msdn.microsoft.com/1ec7db13-3363-46c9-851f-1ce455f66970

Ответ 3

Это субъективный ответ, но я бы сказал, что реальное выражение здесь: "Я просто пытался использовать Code Contracts, и я не вижу никаких реальных преимуществ перед Unit Test"

Пример:

private void Foo(string something) 
{
    Contract.Requires<ArgumentNullException>(something != null, "something");
}

эквивалентен (проверка NUnit):

void Foo(string something) 
{
    if (something == null) 
        throw new ArgumentNullException();
}

[Test]
[ExpectedException( typeof( ArgumentNullException ) )]
void foo_throws_exception_with_null_param() 
{
    Foo(null);
}

Что лучше? Хорошо из моего (ограниченного) опыта добавление статического анализа для VS довольно медленно. Если вы сделали вызов foo с явной нулевой переменной, он подберет его. Но он не будет загружать нулевые значения, загруженные динамически, и отправлять на foo во время итерации пользователя.

С другой стороны, если у вас есть if-statement и unit test, чтобы убедиться, что он выкинет ArgumentNullException, тогда вы знаете, что исключение будет выброшено; и вы можете справиться с ним в среде выполнения... вы можете протестировать все, что использует foo, чтобы убедиться, что оно обрабатывает исключение.

Обеспечение того, что явная проверка выполняется очень быстро с помощью NUnit. Нижняя сторона модульного тестирования - это настройка тестов для начала. Поэтому я считаю, что со временем вы сэкономите больше времени, будучи явным, делая модульные тесты и гарантируя, что ваше приложение сможет справиться, если будут выбрасываться эти исключения... для начала нужно будет просто потратить больше средств.

Ответ 4

Да, кодовые контракты будут предупреждать вас во время компиляции, если нарушен договор, если вы включите статическую проверку. Он подтвердил дополнения Code Contract (Code Contracts for.NET) работает только в Visual Studio 2013 или более поздних версиях, но не в Visual Studio 2015 или 2017.

В Visual Studio 2013: введите описание изображения здесь

В Visual Studio 2015 мы можем увидеть информацию об ошибке из окна "Вывод", но не в окне "Список ошибок". Эта ошибка уже была зарегистрирована и исправлена, но она все равно может быть воспроизведена. Предупреждения и сообщения от статической проверки контрактов не отображаются в списке ошибок VS2015 введите описание изображения здесь


Последнее обновление:
Установите последнюю версию Contracts.devlab9ts.msi(в настоящее время это только версия RC) разрешит проблему в Visual Studio 2015. DotNet CodeContracts v.1.10.20606.1-rc2 введите описание изображения здесь