Плюсы / минусы различных методов тестирования предварительных условий? - PullRequest
17 голосов
/ 15 декабря 2010

Вдобавок ко всему, я могу придумать 4 способа проверить наличие нулевых аргументов:

Debug.Assert(context != null);
Contract.Assert(context != null);
Contract.Requires(context != null);
if (context == null) throw new ArgumentNullException("context");

Я всегда использовал последний метод, но я только видел фрагмент кода, который использовал Contract.Requires, с которым я незнаком. Каковы преимущества / недостатки каждого метода?Есть ли другие способы?


В VS2010 с Resharper,

  • Contract.Assert предупреждает меня, что выражение всегда верно (насколько я знаю, я 'я не совсем уверен ... не может ли HttpContext быть нулевым?),
  • Contract.Requires исчезает, и он говорит мне, что компилятор не будет вызывать метод (я предполагаю, что по предыдущей причине онникогда не будет нулевым), и
  • , если я изменю последний метод на context != null, весь код, следующий за ним, исчезнет, ​​и он скажет мне, что код эвристически недоступен.

Итак, кажется, что последние 3 метода имеют некоторый интеллект, встроенный в статическую проверку VS, и Debug.Assert просто тупой.

Ответы [ 2 ]

12 голосов
/ 15 декабря 2010

Я предполагаю, что к интерфейсу IHttpHandler.ProcessRequest применяется контракт, для которого требуется этот контекст! = Null. Контракты интерфейсов наследуются их исполнителями, поэтому вам не нужно повторять Требование. Фактически вам не разрешено добавлять дополнительные операторы Require, поскольку вы ограничены требованиями, связанными с контрактом на интерфейс.

Я думаю, что важно проводить различие между указанием договорного обязательства и простым выполнением нулевой проверки. Вы можете реализовать нулевую проверку и выдать исключение во время выполнения, чтобы сообщить разработчику, что он правильно использует ваш API. С другой стороны, выражение Контракта на самом деле является формой метаданных, которые могут интерпретироваться разработчиком контракта (для представления исключений времени выполнения, которые ранее были реализованы вручную), а также статическим анализатором, который может использовать их для обоснования о статической корректности вашего заявления.

Тем не менее, если вы работаете в среде, в которой вы активно используете контракты кода и статический анализ, то определенно предпочтительнее поместить утверждения в форму контракта, чтобы воспользоваться преимуществами статического анализа. Даже если вы не используете статический анализ, вы все равно можете оставить дверь открытой для последующих выгод, используя контракты. Главное, на что нужно обратить внимание, - настроили ли вы свои проекты на переписывание, иначе контракты не приведут к исключениям времени выполнения, как вы могли ожидать.


Для уточнения сказанного комментаторами разница между утверждением, предположением и потребностью составляет:

  • Выражение Contract.Assert преобразуется в утверждение переписывателем контракта, и статический анализатор пытается доказать выражение на основе существующих доказательств. Если это невозможно доказать, вы получите предупреждение о статическом анализе.
  • Выражение Contract.Assume игнорируется переписчиком контракта (насколько я знаю), но интерпретируется статическим анализатором как новое доказательство, которое оно может принять во внимание при статическом анализе. Contract.Assume используется для «заполнения пробелов» в статическом анализе, либо там, где ему не хватает изощренности, чтобы сделать необходимые выводы, или при взаимодействии с кодом, который не был оформлен с помощью контрактов, так что вы можете предположить, например, , что конкретный вызов функции возвращает ненулевой результат.
  • Contract.Requires - это условия, которые всегда должны быть истинными при вызове вашего метода. Они могут быть ограничениями параметров для метода (которые являются наиболее типичными), а также могут быть ограничениями для публично видимых состояний объекта (например, вы можете разрешить вызов метода только в том случае, если Initialized имеет значение True.) ограничений заставляет пользователей вашего класса либо проверять Initialized при использовании объекта (и, по-видимому, обрабатывать ошибку соответствующим образом, если это не так), либо создавать свои собственные ограничения и / или инварианты классов, чтобы уточнить, что Initialization действительно произошла.
2 голосов
/ 15 декабря 2010

Первый метод подходит для тестирования нулевого условия, которое никогда не должно существовать.То есть используйте его во время разработки, чтобы убедиться, что он не будет неожиданно установлен в нуль.Поскольку он не обрабатывает ошибки, он не подходит для обработки нулевых условий в вашем выпущенном продукте.

Я бы сказал, что 2-я и 3-я версии похожи в том, что они не решают проблему ниway.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...