Почему CodeContracts предупреждает меня, что «требуется недоказанное: индекс <@ this.Count», хотя я уже проверил счетчик? - PullRequest
8 голосов
/ 28 июля 2011

У меня есть код, который выглядит примерно так:

public class Foo<T> : ObservableCollection<T>
{
    private T bar;

    public Foo(IEnumerable<T> items)
        : base(items.ToList())
    {
        Contract.Requires(items != null);

        if (this.Any())
            this.bar = this[0]; // gives 'requires unproven: index < @this.Count'
    }
}

Разве Any не должен проверять учетную запись на индекс 0? Я что-то не так делаю или CodeContracts просто не распознает этот случай?

Ответы [ 2 ]

6 голосов
/ 28 июля 2011

Ни один из методов LINQ не аннотирован с помощью Contracts API. Следовательно, когда верификатор работает по этому методу, он не получает новых данных о значении Count. Вот почему вы видите предупреждение.

Один из способов обойти это - использовать Assume, чтобы сообщить верификатору, что счет действителен в данный момент.

if (this.Any()) {
  Contract.Assume(this.Count > 0);
  this.bar = this[0];
}
6 голосов
/ 28 июля 2011

LINQ .Any и средство доступа к элементу [0] не связаны между собой настолько, что не были заключены контракты по кодам, чтобы считать их одним и тем же.Поскольку this.bar в любом случае будет инициализироваться с использованием значения по умолчанию, лучше всего просто сделать это:

Contract.Requires(items != null);
this.bar = items.FirstOrDefault();

Это не только разрешит возможность обеспечения безопасности потоков, на которую указывает AakashM, но такженемного более производительный.Поскольку вы знаете, this является коллекцией (и поэтому имеет .Count), другой вариант будет:

if(this.Count > 0)
    this.bar = this[0]; 
...