Если я напишу это:
public sealed class Foo
{
private int count;
private object owner;
private void Bar()
{
Contract.Requires(count > 0);
Contract.Ensures(owner == null || count > 0);
if (count == 1)
owner = null;
--count;
}
}
Статическая проверка контракта может подтвердить все утверждения.
Но если я напишу это вместо:
public sealed class Foo
{
private int count;
private object owner;
private void Bar()
{
Contract.Requires(count > 0);
Contract.Ensures(owner == null || count > 0);
--count;
if (count == 0)
owner = null;
}
}
Он утверждает, что постусловие owner == null || count > 0
недоказано.
Я думаю, что могу доказать, что вторая форма не нарушает это постусловие:
// { count > 0 } it's required
--count;
// { count == 0 || count > 0 } if it was 1, it's now zero, otherwise it's still greater than zero
if (count == 0)
{
// { count == 0 } the if condition is true
owner = null;
// { count == 0 && owner == null } assignment works
}
// { count == 0 && owner == null || count != 0 && count > 0 } either the if was entered or not
// { owner == null || count > 0 } we can assume a weaker postcondition
Что-то не так с моим доказательством?
Я добавил утверждения в своем доказательстве, когда Contract.Assert
вызывает код, и пришел к выводу, что если я добавлю только это, ему удастся доказать постусловие:
--count;
Contract.Assert(count == 0 || count > 0)
if (count == 0)
owner = null;
Но, если я теперь изменю это же утверждение на "более естественный" способ, он потерпит неудачу:
--count;
Contract.Assert(count >= 0)
if (count == 0)
owner = null;
Можно ожидать, что эти два утверждения были эквивалентны, но статическая проверка обрабатывает их по-разному.
(кстати, я использую бета-версию 2 VS10)