C # - кодовые контракты - обнаружен оператор выражения, оцененный для потенциального побочного эффекта - PullRequest
3 голосов
/ 20 января 2012

Я только начал использовать CodeContracts с C #, и мне может понадобиться помощь. У меня есть класс со статическим списком ключей, и у меня есть статический метод Remove (), который удаляет ключ из этого списка.

Теперь из условий публикации контрактов я понимаю, что, будучи программистом класса, я гарантирую, что текущий публичный метод сделает что-то конкретное, в данном случае: удаление элемента списка.

Вот что я написал:

    private static List<Keys> m_usedKeys; // private list of keys

    public static void Remove(Keys _key)
    {
        m_usedKeys.Remove(_key);
        Contract.Ensures(!m_usedKeys.Any(x => x == _key));
    }

Здесь я пытаюсь «убедиться» в том, что метод Remove () удаляет ключ real из списка (да, это может быть тривиальный пример, но я получаю ошибку там).

когда я пишу строку Contract.Ensures (), VS2010 выдает мне следующую ошибку:

Error   3   Detected expression statement evaluated for potential side-effect in contracts of method 'LibJungleTimer.KeyBind.Remove(System.Windows.Forms.Keys)'. (Did you mean to put the expression into a Requires, Ensures, or Invariant call?)  C:\Users\Joel\Documents\Programmation\JT\JungleTimer\LibJungleTimer\KeyBind.cs  51

Я думаю, что эта ошибка говорит о том, что выражение m_usedKeys.remove(_key); имеет потенциальный побочный эффект. Фактически, у него есть побочный эффект, он удаляет ключ из списка!

Если я попытаюсь написать что-то вроде этого:

Contract.Assert(!m_usedKeys.Any(x => x == _key));

ну, это хорошо компилируется. Мой вопрос: что я делаю не так? Разве CodeContracts не должен использоваться таким образом, чтобы обеспечить условия публикации?

РЕДАКТИРОВАТЬ: Да, я действительно имел в виду! M_usedKeys.Any (...);

1 Ответ

11 голосов
/ 20 января 2012

Инструмент Code Contracts предполагает, что все до последнего Contract.Ensures / Contract.Requires является частью контракта ... поэтому он считает, что ваш вызов Remove является частью контракта, а не частью реализации. Вы должны полностью изменить свой код, чтобы весь код контракта был до реализации.

public static void Remove(Keys _key)
{
    Contract.Ensures(m_usedKeys.Any(x => x == _key));        
    m_usedKeys.Remove(_key);
}

Я подозреваю, что вы хотите !m_usedKeys.Any(...), кстати ... и я бы тоже с осторожностью отнесся к этому коду, учитывая, что у вас нет защиты от потоков. Меня не беспокоило бы, если бы это был метод экземпляра, но статические методы, обращающиеся к статическому (то есть глобальному) состоянию, как правило, должны быть поточно-ориентированными.

...