Я пытаюсь продемонстрировать инварианты в контрактах кода, и я подумал, что приведу пример отсортированного списка строк. Он поддерживает массив внутри, с запасным пространством для дополнений и т. Д. - как и List<T>
, в основном. Когда ему нужно добавить элемент, он вставляет его в массив и т. Д. Я подумал, что у меня есть три инварианта:
- Количество должно быть разумным: неотрицательным и максимально большим, чем размер буфера
- Все в неиспользуемой части буфера должно быть нулевым
- Каждый элемент в используемой части буфера должен быть по крайней мере таким же «большим», как и элемент перед ним
Теперь я попытался реализовать это следующим образом:
[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 . Я сам добавлю сюда любые соответствующие ответы.)