Проверка аргументов функции? - PullRequest
4 голосов
/ 04 февраля 2009

Регулярно проверяю аргументы своей функции:


public static void Function(int i, string s)
{
  Debug.Assert(i > 0);
  Debug.Assert(s != null);
  Debug.Assert(s.length > 0);
}

Конечно, проверки являются «действительными» в контексте функции.

Это обычная отраслевая практика? Что является обычной практикой в ​​отношении проверки аргументов функции?

Ответы [ 9 ]

10 голосов
/ 04 февраля 2009

Принятая практика заключается в следующем, если значения недействительны или в дальнейшем вызовут исключение:

if( i < 0 )
   throw new ArgumentOutOfRangeException("i", "parameter i must be greater than 0");

if( string.IsNullOrEmpty(s) )
   throw new ArgumentNullException("s","the paramater s needs to be set ...");

Итак, список исключений базовых аргументов выглядит следующим образом:

ArgumentException
ArgumentNullException
ArgumentOutOfRangeException
5 голосов
/ 04 февраля 2009

То, что вы написали, - предварительные условия и важный элемент Проектирование по контракту . Google (или "StackOverflow" :) для этого термина, и вы найдете довольно много хорошей информации о нем, а также некоторую плохую информацию. Обратите внимание, что метод включает также постусловий и концепцию инварианта класса .

Давайте оставим ясно, что утверждения являются действительным механизмом.

Конечно, они обычно ( не всегда ) не проверены в режиме Release, так что это означает, что вы должны проверить свой код перед его выпуском.

Если утверждения оставлены включенными и утверждение нарушено, стандартное поведение в некоторых языках, в которых используются утверждения (и в частности в Eiffel), - генерировать исключение нарушения утверждения.

Утверждения, которые не проверены, являются , а не удобным или желательным механизмом, если вы публикуете библиотеку кодов, или (очевидно) способом проверки прямого, возможно, неверного ввода. Если у вас «возможно неправильный ввод», вы должны разработать как часть нормального поведения вашей программы проверку ввода layer ; но вы все еще можете свободно использовать утверждения во внутренних модулях.


Другие языки, такие как Java, имеют более традиционную явную проверку аргументов и выдачу исключений, если они ошибочны , главным образом потому, что эти языки не имеют строгого "утверждения" или "дизайна договор "традиция.

(Некоторым это может показаться странным, но я нахожу различия в традициях респектабельными и необязательно злыми.)

См. Также этот связанный вопрос .

3 голосов
/ 04 февраля 2009

Вы не должны использовать утверждения для проверки данных в реальном приложении. Насколько я понимаю, утверждения предназначены для проверки правильности использования функции. Или что функция возвращает правильное значение, т.е. ценность, которую вы получаете, это то, что вы ожидали. Они часто используются в рамках тестирования. Они предназначены для отключения, когда система развернута, поскольку они работают медленно. Если вы хотите обработать недействительные случаи, вы должны сделать это явно, как указано выше.

2 голосов
/ 05 февраля 2009

Для общедоступных функций, особенно вызовов API, вы должны выдавать исключения. Потребители, вероятно, были бы благодарны, если бы знали, что в их коде есть ошибка, и исключение составляет гарантированный способ сделать это.

Для внутренних или частных функций Debug.Assert хорошо (но не обязательно, IMO). Вы не будете принимать неизвестные параметры, и ваши тесты должны перехватывать любые недопустимые значения по ожидаемому результату. Но иногда Debug.Assert позволит вам сосредоточиться или предотвратить ошибку намного быстрее.

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

Хотя вы хотите проверять аргументы, вам не нужны 4 уровня проверки, которые вы должны синхронизировать (и платить за штраф). Итак, проверьте на внешнем интерфейсе и просто верьте, что вы и ваши коллеги способны надлежащим образом вызывать функции и / или исправлять ошибку, которая неизбежно приводит к.

2 голосов
/ 04 февраля 2009

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

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

Debug.Assert в вашей функции просто для того, чтобы помочь ВАМ отлаживать, это хорошая первая линия защиты, но это не «настоящая» проверка.

1 голос
/ 05 февраля 2009

Вы должны использовать Assert для проверки программных предположений; то есть для ситуации, когда

  1. вы единственный, кто вызывает этот метод
  2. это должно быть невозможное состояние, чтобы войти в

Операторы Assert позволят вам дважды проверить, что невозможное состояние никогда не достигается. Используйте это там, где вы могли бы чувствовать себя комфортно без проверки.

В ситуациях, когда функция получает неверные аргументы, но вы можете видеть, что она не может получить эти значения (например, когда кто-то другой может вызвать этот код), вы должны выбросить исключения (а @ Натан W и @ Роберт Полсон ) или изящный провал (а-ля @ Срджан Пежич ).

1 голос
/ 04 февраля 2009

Большую часть времени я не использую Debug.Assert, я бы делал что-то вроде этого.

public static void Function(int i, string s)
{
  if (i > 0 || !String.IsNullOrEmpty(s))
         Throw New ArgumentException("blah blah");
}

ВНИМАНИЕ: Это воздушный код, я его не проверял.

0 голосов
/ 04 февраля 2009

Я стараюсь не использовать Debug.Assert, скорее я пишу охранники. Если параметр функции не имеет ожидаемого значения, я выхожу из функции. Как это:

public static void Function(int i, string s)
{
    if(i <= 0)
    {
        /*exit and warn calling code */
    }
}

Я считаю, что это уменьшает количество споров, которые должны произойти.

0 голосов
/ 04 февраля 2009

Я не буду говорить о отраслевых стандартах, но вы можете объединить два нижних утверждения в одну строку:

Debug.Assert(!String.IsNullOrEmpty(s));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...