Контракты кода: Почему некоторые инварианты не рассматривают вне класса?

Рассмотрите этот неизменный тип:

public class Settings
{
    public string Path { get; private set; }

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

    public Settings(string path)
    {
        Contract.Requires(path != null);
        Path = path;
    }
}

Две вещи заметить здесь:

  • Существует инвариант контракта, который удостоверяется Path свойство никогда не может быть null
  • Конструктор проверяет path значение аргумента для уважения предыдущего инварианта контракта

На данном этапе a Setting экземпляр никогда не может иметь a null Path свойство.

Теперь, посмотрите на этот тип:

public class Program
{
    private readonly string _path;

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

    public Program(Settings settings)
    {
        Contract.Requires(settings != null);
        _path = settings.Path;
    } // <------ "CodeContracts: invariant unproven: _path != null"
}

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

  • settings неизменно
  • settings.Path не может быть пустым (потому что Настройки имеют соответствующий инвариант контракта),
  • таким образом путем присвоения settings.Path кому: _path, _path не может быть пустым

Я пропускал что-то здесь?

12
задан Pascal Cuoq 29 July 2010 в 15:18
поделиться

1 ответ

После проверки на форуме контрактов кода я нашел этот аналогичный вопрос со следующим ответом от одного из разработчиков:

Я думаю, что ваше поведение вызвано некоторый межметодный вывод, который происходит. Статическая проверка сначала анализирует конструкторы, затем свойства, а затем методы. При анализе конструктора Sample он не знает, что msgContainer.Something! = Null, поэтому выдает предупреждение. Решить эту проблему можно либо путем добавления предположения msgContainer.Something! = Null в конструктор, либо лучше добавить постусловие! = Null в Something.

Другими словами, у вас есть следующие варианты:

  1. Сделайте свойство Settings.Path явным, а не автоматическим, и вместо этого укажите инвариант в поле поддержки. Чтобы удовлетворить ваш инвариант, вам нужно будет добавить предварительное условие к методу доступа set свойства: Contract.Requires (value! = Null) .

    При желании вы можете добавить постусловие в метод доступа get с помощью Contract.Ensures (Contract.Result ()! = Null) , но статическая проверка не будет жаловаться в любом случае.

  2. Добавьте Contract.Assume (settings.Path! = Null) в конструктор класса Program .

10
ответ дан 2 December 2019 в 22:21
поделиться
Другие вопросы по тегам:

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