Повторять кодовые требования контракта вниз по цепочке наследования?

Предположим, у вас уже есть крупный проект, и вы хотите интегрировать в него контракты по коду. В существующем коде используется логика if-null-then-throw. Для заданных условий в документации предлагается установить режим сборки на Custom Validation Validation.

У меня есть следующие классы:

class A
{
    protected virtual void Foo(int a, int b)
    {
        if (a == null)
            throw new ArgumentNullException(a);
        if (b == null)
            throw new ArgumentNullException(b);
        Contract.EndContractBlock();
    }
}
class B : A
{
    protected override void Foo (int a, int b)
    {
        // some stuff
        base.Foo(a, b);
    }
}

Когда я компилирую, я получаю следующее предупреждение:

предупреждение CC1055: метод "B.Foo(int, int)" должен содержать пользовательскую проверку аргумента для "Requires(a!= null)", так как он переопределяет "A.Foo(int,int)", что предполагает его. Если вы не хотите использовать пользовательскую проверку аргументов в этой сборке, измените режим сборки на "Требуется стандартный контракт".

Я не хочу повторять предварительные условия для каждого переопределенного метода! Есть ли способ обойти это?

1 ответ

Решение

Работает нормально, если вы используете Contract.Requires() вместо Contract.EndContractBlock(),

В руководстве, приведенном ниже, есть раздел, в котором предлагается добавить [SuppressMessage] атрибут переопределения метода.

Из руководства пользователя Code Contracts стр.22 раздел 5.2.3.

Делегирование проверок другим методам

Предположим, у вас есть шаблон кода, похожий на следующий код:

public class Base {
    public virtual void Compute(string data) {
    if (data == null) throw new ArgumentNullException(...);
        Contract.EndContractBlock();
        ...
    }
}

public class Derived : Base {
    public override void Compute(string data) {
        base.Compute(data);
        ...
    }
}

Затем утилита выдаст предупреждение CC1055 с сообщением вида:

Метод "Derived.Compute" должен содержать пользовательскую проверку аргумента для "Requires (ArgumentNullException)(data! = Null)", так как он переопределяет "Base.Compute", что и предполагает.

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

public class Derived : Base {
    [SuppressMessage("Microsoft.Contracts", "CC1055", Justification = "Validation performed in base method")]
    public override void Compute(string data) {
        base.Compute(data);
        ...
    }
}
Другие вопросы по тегам