Код контрактов - Предположим против Требуется - PullRequest
32 голосов
/ 21 января 2011

В чем разница между этими двумя утверждениями?

Contract.Requires(string.IsNullOrWhiteSpace(userName));

Contract.Assume(string.IsNullOrWhiteSpace(userName));

Ответы [ 3 ]

63 голосов
/ 23 января 2011

Представьте, что у вас есть метод, подобный следующему:

bool ContainsAnX(string s)
{
    return s.Contains("X");
}

Теперь этот метод всегда завершится ошибкой, если вы передадите ему null, поэтому вы хотите убедиться, что этого никогда не произойдет.Вот для чего Contract.Requires.Он устанавливает предварительное условие для метода, которое должно быть истинным, чтобы метод работал правильно.В этом случае мы должны иметь:

bool ContainsAnX(string s)
{
    Contract.Requires(s != null);

    return s.Contains("X");
}   

( Примечание : Requires и Ensures всегда должны быть в начале метода, поскольку они представляют собой информацию о методе какцелое. Assume используется в самом коде, так как это информация об этой точке в коде.)

Теперь, в вашем коде, который вызывает метод "ContainsAnX", вы должны убедиться, что строкане является нулевымВаш метод может выглядеть следующим образом:

void DoSomething()
{
    var example = "hello world";

    if (ContainsAnX(example))
        Console.WriteLine("The string contains an 'X'.");
    else
        Console.WriteLine("The string does not contain an 'X'.");
}

Это будет работать нормально, и статическая проверка может доказать, что example не равен нулю.

Однако вы можете вызывать внешние библиотеки, которые не имеют никакой информации о значениях, которые они возвращают (т.е. они не используют кодовые контракты).Давайте изменим пример:

void DoSomething()
{
    var example = OtherLibrary.FetchString();

    if (ContainsAnX(example))
        Console.WriteLine("The string contains an 'X'.");
    else
        Console.WriteLine("The string does not contain an 'X'.");
}

Если OtherLibrary не использует кодовые контракты, статическая проверка будет жаловаться, что example может быть нулевым.

Возможно, их документация длябиблиотека говорит, что метод никогда не вернет ноль (или должен никогда!).В этом случае мы знаем больше, чем статическая проверка, поэтому мы можем сказать Assume, что переменная никогда не будет нулевой:

void DoSomething()
{
    var example = OtherLibrary.FetchString();

    Contract.Assume(example != null);

    if (ContainsAnX(example))
        Console.WriteLine("The string contains an 'X'.");
    else
        Console.WriteLine("The string does not contain an 'X'.");
}

Теперь это будет хорошосо статической проверкой.Если у вас включены контракты во время выполнения, Assume также будет проверяться во время выполнения.

Другой случай, когда вам может потребоваться Assume, - это когда ваши предварительные условия очень сложны, и статическая проверка испытывает трудности с их подтверждением.В этом случае вы можете слегка подтолкнуть его, чтобы помочь ему:)

С точки зрения поведения во время выполнения не будет большой разницы между использованием Assume и require.Однако результаты со статической проверкой будут сильно отличаться.Значение каждого также различно с точки зрения того, кто несет ответственность за ошибку в случае сбоя:

  • Требуется означает, что код, вызывающий этот метод должен обеспечить выполнение условия.
  • Предполагается, что этот метод делает предположение, которое всегда должно выполняться.
2 голосов
/ 21 января 2011

Отличается только временем разработки / статическим анализом

Contract.Assume: «Поручает инструментам анализа кода предположить, что указанное условие является истинным, даже если оно не может быть статически доказано, что оно всегда выполняется» А также: Во время выполнения использование этого метода эквивалентно использованию метода Assert (Boolean).

Contract.Requires гарантирует, что данный предикат верен, и статические анализаторы кода могут вызвать ошибку, если они не могут «доказать», что это не так. По контракту. Предположим, что статический анализатор продолжит / выдаст предупреждение / независимо от того, какой инструмент примет решение.

0 голосов
/ 23 декабря 2017

Согласно официальной документации : страницы 7 (предварительные условия) и 11 (предполагается).

Требуется:

  • Является липредварительное условие («предварительные условия извлекаются с использованием Contract.Requires»);
  • В качестве предварительного условия будет выполняться при вызове метода;

Предполагается:

  • Не предусловие, не постусловие, не инвариант;
  • Выполняется в том месте, где оно указано;
  • p.11 «Существовать в сборке, только если определен символ полного контракта или символ ОТЛАДКИ»;
...