Я пытаюсь продемонстрировать инварианты в Code Contracts, и я подумал, что приведу пример отсортированного списка строк. Он поддерживает массив внутри, с запасным пространством для дополнений и т.д. - в основном как List<T>
. Когда ему нужно добавить элемент, он вставляет его в массив и т.д. Я решил, что у меня есть три инварианта:
- Счет должен быть разумным: неотрицательным и не более большим, чем размер буфера
- Все в неиспользуемой части буфера должно быть null
- Каждый элемент в используемой части буфера должен быть по крайней мере как "большой", как элемент перед ним
Теперь я попытался реализовать это следующим образом:
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(count >= 0 && count <= buffer.Length);
for (int i = count; i < buffer.Length; i++)
{
Contract.Invariant(buffer[i] == null);
}
for (int i = 1; i < count; i++)
{
Contract.Invariant(string.Compare(buffer[i], buffer[i - 1]) >= 0);
}
}
К сожалению, ccrewrite
запутывает циклы.
В документации пользователя говорится, что метод должен быть просто последовательностью вызовов Contract.Invariant
. Должен ли я переписать код как-то вроде этого?
Contract.Invariant(count >= 0 && count <= buffer.Length);
Contract.Invariant(Contract.ForAll
(count, buffer.Length, i => buffer[i] == null));
Contract.Invariant(Contract.ForAll
(1, count, i => string.Compare(buffer[i], buffer[i - 1]) >= 0));
Это несколько уродливое, хотя оно действительно работает. (Это намного лучше, чем моя предыдущая попытка, заметьте.)
Неужели мои ожидания необоснованны? Являются ли мои инварианты необоснованными?
(Также задан как вопрос в форуме Code Contracts. Я сам добавлю соответствующие ответы.)