Кодовые контракты - Требуется / Гарантирует недоказанность, когда я использую IComparable или IComparable <T> - PullRequest
0 голосов
/ 25 февраля 2012

У меня есть следующий метод:

public static bool IsBetween<T>(this IComparable<T> value, T lowerBound, T upperBound)
    where T : IComparable<T>
{
    Contract.Requires<>(value != null);
    Contract.Requires<>(lowerBound != null);
    Contract.Requires<>(upperBound != null);
    Contract.Requires<>(upperBound.CompareTo(lowerBound) >= 0);

    return IsBetween(value, lowerBound, upperBound, InclusionOptions.None);
}

public static bool IsBetween<T>(this IComparable<T> value, T lowerBound, T upperBound,
     InclusionOptions options) where T : IComparable<T>
{
    Contract.Requires<>(value != null);
    Contract.Requires<>(lowerBound != null);
    Contract.Requires<>(upperBound != null);
    Contract.Requires<>(upperBound.CompareTo(lowerBound) >= 0); //Code Contracts Issue

    ...
}

Проблема здесь в том, что ему не нравится мое последнее требование. Это заявляет CodeContracts: requires unproven: upperBound.CompareTo(lowerBound) >= 0. Я не совсем уверен, как правильно исправить это здесь. Мне нужно убедиться, что когда я делаю мои значения сравнения, у меня действительно есть реальное значение lowerBound и upperBound и что значение lowerBound не выше значения upperBound.

О, и я не могу использовать фактические операторы <или>, потому что вы не можете применить их к типу 'T'.


Наконец, я знаю, что может быть отдельным вопросом, но он тесно связан ... если кто-то знает, почему я все еще получаю ошибки анализа кода CA1062 при использовании Code Contracts v1.4.50126.1 подскажите пожалуйста что нужно сделать чтобы это исправить: CA1062: Microsoft.Design : In externally visible method 'MyClass.IsBetween<T>(this IComparable<T>, T, T), validate parameter 'upperBound' before using it.

Ответы [ 2 ]

0 голосов
/ 29 февраля 2012

Я буду использовать int в качестве примера.

Контракт на int.CompareTo(int) не гарантирует какого-либо конкретного возвращаемого значения. Вы знаете, что если a >= b, то a.CompareTo(b) >= 0, но, поскольку это не было выражено в качестве контракта, единственное, что видит статическая проверка, это "a.CompareTo (b) возвращает int".«Int» не может быть доказано, что оно неотрицательно.

Вы должны иметь возможность добавить что-то вроде

Contract.Assert(a >= b);
Contract.Assume(a.CompareTo(b) >= 0);

в тех местах, где вы вызываете свою функцию.Это позволяет статической проверке сначала попытаться доказать это a >= b и уведомить вас, если она не может этого доказать, а затем доверять вам, что требование функции выполнено.

Если вы часто вызываете эту функцию для intможет быть целесообразно создать функцию-оболочку с этим измененным int -конкретным контрактом:

public static bool IsBetween(this int value, int lowerBound, int upperBound)
{
    Contract.Requires<>(value != null);
    Contract.Requires<>(lowerBound != null);
    Contract.Requires<>(upperBound != null);
    Contract.Requires<>(upperBound >= lowerBound);
    Contract.Assume(upperBound.CompareTo(lowerBound) >= 0);
    return IsBetween<int>(value, lowerBound, upperBound);
}

и аналогично для других типов.

0 голосов
/ 25 февраля 2012

Проблема с вашим методом заключается в том, что при вызове upperBound.CompareTo вы предполагаете, что компилятор знает, что тип T (который является объявленным типом параметра upperBound) реализует интерфейс IComparable<T> ( который объявляет метод CompareTo).

Как правило, всегда (по соглашению) реализуется интерфейс IComparable<T> с типом T (если вообще); однако компилятор не узнает об этом, если вы явно не укажете его через ограничение типа.

public static bool IsBetween<T>(this T value, T lowerBound, T upperBound)
    where T : IComparable<T>
{
    Contract.Requires(value != null);
    Contract.Requires(lowerBound != null);
    Contract.Requires(upperBound != null);
    Contract.Requires(upperBound.CompareTo(lowerBound) >= 0);

    // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...