Подтвердить что ты не робот

Контракт кода [Тип] реализует метод интерфейса {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, и если я добавлю контракт, он даст мне ошибку

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

Какая самая лучшая вещь здесь? Параметры, которые я вижу, включают

  • оговорка о защите, хотя кажется бит экстремальный
  • a Contract.Assume
  • скрытый третий вариант, о котором я не думал

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

4b9b3361

Ответ 1

Описание

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

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

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

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

Решение

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

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

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

Можно добавить в конструктор postcondition Contract.Ensures(_somethingElse != null);, но статическая проверка не требует его.