Рассмотрите этот неизменный тип:
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
не может быть пустымЯ пропускал что-то здесь?
После проверки на форуме контрактов кода я нашел этот аналогичный вопрос со следующим ответом от одного из разработчиков:
Я думаю, что ваше поведение вызвано некоторый межметодный вывод, который происходит. Статическая проверка сначала анализирует конструкторы, затем свойства, а затем методы. При анализе конструктора Sample он не знает, что msgContainer.Something! = Null, поэтому выдает предупреждение. Решить эту проблему можно либо путем добавления предположения msgContainer.Something! = Null в конструктор, либо лучше добавить постусловие! = Null в Something.
Другими словами, у вас есть следующие варианты:
Сделайте свойство Settings.Path
явным, а не автоматическим, и вместо этого укажите инвариант в поле поддержки. Чтобы удовлетворить ваш инвариант, вам нужно будет добавить предварительное условие к методу доступа set свойства: Contract.Requires (value! = Null)
.
При желании вы можете добавить постусловие в метод доступа get с помощью Contract.Ensures (Contract.Result
, но статическая проверка не будет жаловаться в любом случае.
Добавьте Contract.Assume (settings.Path! = Null)
в конструктор класса Program
.