Контракты кода [Type] реализуют метод интерфейса {Interface.Method}, поэтому не могут добавлять требования

У меня следующий сценарий:

public interface ISomething
{
    void DoStuff();
    //...
}

public class Something : ISomething
{
    private readonly ISomethingElse _somethingElse;
    //...

    public Something (ISomethingElse somethingElse)
    {
         Contract.Requires(somethingElse != null);
        _somethingElse = somethingElse;
    }

    public void DoStuff()
    {
        // *1* Please look at explanation / question below
        _somethingElse.DoThings();
    }
 }

В строке 1 и при включенной статической проверке я получаю предупреждение о том, что _somethingElse возможно имеет значение null, и если я добавлю контракт, это приведет к ошибке

[Type] реализует метод интерфейса {Interface. Таким образом, метод} не может добавить требует

Что лучше всего здесь сделать? Варианты, которые я вижу, включают

  1. защитную оговорку, хотя это кажется немного экстремальным
  2. Контракт. Примите
  3. скрытый третий вариант, о котором я не подумал

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

21
задан Kit 18 May 2011 в 20:21
поделиться

1 ответ

Объяснение

Раздел 3: Наследование контракта руководства пользователя утверждает, что все предварительные условия должны быть определены в корневом методе цепочки наследования / реализации:

Если клиент удостоверяется, что он выполнил предварительное условие и имеет переменную o , статический тип которой равен T , то клиент не должен получать нарушение предусловия при вызове OM . Это должно быть верно, даже если значение времени выполнения o имеет тип U . Следовательно, метод U.M не может добавить предусловие, которое сильнее, чем предусловие T.M .

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

Как следствие, предварительные условия метода должны быть объявлены в корневом методе цепочки наследования / реализации, то есть в первом объявлении виртуального или абстрактного метода или в самом методе интерфейса.

Решение

В вашей ситуации лучший способ действий - установить инвариант, утверждающий, что поле _somethingElse никогда не будет нулевым:

[ContractInvariantMethod]
private void ObjectInvariant() {
    Contract.Invariant(_somethingElse != null);
}

Это, конечно, всегда верно, поскольку поле помечен только для чтения и инициализируется в конструкторе. Статическая проверка не может сделать этого сама по себе, поэтому вы должны явно указать это через этот инвариант.

При желании вы можете добавить постусловие Contract.Ensures (_somethingElse! = Null); в свой конструктор, но статическая проверка этого не требует.

19
ответ дан 29 November 2019 в 21:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: