2016-11-02 4 views
1

Этот вопрос касается соглашения и интерпретации MSDN, поэтому я не думаю, что это основано прежде всего на мнениях.Должен ли я бросать исключение ArgumentException?

Мне интересно, ArgumentException: У меня есть класс строителя, который используется для создания объекта фильтра, который будет применяться при получении набора сообщений электронной почты из почтового ящика. У конструктора есть несколько способов для установки параметров фильтра. Например, у меня есть два метода для установки диапазона «дата отправки» фильтра, отправленного до XX и/или отправленного после XX. Я хочу добавить предложение охраны для каждого, которое будет генерировать исключение, если, например, предоставленная «до» дата равна после предоставленной «после» даты. Я хотел бы сделать это с помощью общего метода проверки:

/// <summary> 
/// This class provides methods for validating dates in various ways. 
/// </summary> 
internal static class DateValidation 
{ 
    /// <summary> 
    /// Validate the provided "start" and "end" date/time values. 
    /// If they do not represent a valid range, throw an exception. 
    /// </summary> 
    /// <param name="start">The date/time that represents the start of the range.</param> 
    /// <param name="end">The date/time that represents the end of the range.</param> 
    internal static void ValidateDateTimeRange(DateTime? start, DateTime? end) 
    { 
     if (start.HasValue && end.HasValue) 
     { 
      if (start.Value > end.Value) 
       throw new Exception(
       string.Format(@"The start date/time ""{0}"" " + 
       @"occurs after the end date/time ""{1}"".", 
       start.ToString(), end.ToString())); 
     } 
    } 
} 

Вот методы два строителя:

/// <summary> 
/// Set a value which represents a date/time after which 
/// messages must have been sent to be part of filtered output. 
/// </summary> 
/// <param name="afterDateTime">The date/time after which 
/// messages must have been sent to be part of filtered output.</param> 
public void SetSentAfterDateTime(DateTime afterDateTime) 
{ 
    DateValidation.ValidateDateTimeRange(afterDateTime, _sentBeforeDateTime); 
    _sentAfterDateTime = afterDateTime; 
} 

/// <summary> 
/// Set a value which represents a date/time before which 
/// messages must have been sent to be part of filtered output. 
/// </summary> 
/// <param name="beforeDateTime">The date/time before which 
/// messages must have been sent to be part of filtered output.</param>  
public void SetSentBeforeDateTime(DateTime beforeDateTime) 
{ 
    DateValidation.ValidateDateTimeRange(_sentAfterDateTime, beforeDateTime); 
    _sentBeforeDateTime = beforeDateTime; 
} 

По словам MSDN:

Чаще ArgumentException является Брошенный общий язык runtime или другую библиотеку классов и указывает ошибку разработчика.

Я получаю, что фраза «чаще всего» оставляет возможность открытой для других обычаев, как моя, но мне нравится придерживаться конвенции. Я создаю открытый API, поэтому исключение будет задокументировано и выйдет за пределы открытого интерфейса; кроме того, он не указывает на ошибку разработчика. Это может, предположительно, указывать на ошибку пользователя (это общепринятое соглашение об использовании исключений для решения проблем проверки входных данных пользователя). Я чувствую, основываясь на описании MSDN, однако, что это не то, для чего он предназначен.

... Производные классы [ArgumentNullException и ArgumentOutOfRangeException] должен быть использован вместо ArgumentException, за исключением того, в ситуациях, когда ни один из производных классов является приемлемым. Например, исключения должны быть брошено:

...

ArgumentOutOfRangeException, когда значение аргумента находится вне диапазона допустимых значений; например, когда значение «46» равно , принятое в качестве аргумента месяца при создании DateTime.

Мой аргумент может быть вне диапазона допустимых значений, но это условие определяется динамически на основе другого значения даты/времени. Нет статического диапазона значений, которые «вне диапазона».

Значит, ArgumentException обычно используется для таких случаев?

+3

Я бы не согласился с утверждением: «Общим соглашением является использование исключений для решения проблем проверки ввода пользователя». Разработчик, который использует ваш API, отвечает за проверку ввода пользователя перед передачей его функции. Если пользователь предоставляет недопустимый ввод и разработчик не поймает его, прежде чем передавать его в вашу функцию, это «ошибка разработчика». –

+0

Хорошая точка. Согласен. –

+0

_ «Этот вопрос касается соглашения и интерпретации MSDN, поэтому я не думаю, что в первую очередь это основано на мнениях», - прося что-либо, кроме буквального чтения MSDN, вы, безусловно, задаете вопрос «в первую очередь мнение» , Конвенции, по определению, субъективны и даже там, где некоторая конвенция была документирована, если вы хотите, чтобы отдельные интерпретации этой документации выходили за рамки того, что буквально представлено в документации, это может быть также субъективным. –

ответ

6

С How to Design Exception Hierarchies по Кшиштоф Квалина:

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

Согласен, что это ошибка использования.

Эрик Липперт называет их Boneheaded exceptions:

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

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

Как Cwalina объясняет:

ошибки использования должна быть доведена до сведения человека разработчика вызывающего процедуры. Тип исключения не лучший способ передавать ошибки людям. Строка сообщения намного лучше. Поэтому для исключений, которые возникают в результате ошибок использования, я хотел бы сконцентрироваться на создании действительно хорошего (то есть объяснительного) сообщения об исключении и использовании одного из существующих типов исключений .NET Framework: ArgumentNullException, ArgumentException, InvalidOperationException, NotSupportedException и т. Д. Другими словами, не создавайте новые типы исключений для ошибок использования, поскольку тип исключения не имеет значения для ошибок использования. У .NET Framework уже есть достаточно типов (на самом деле слишком много, IMHO), чтобы представлять каждую ошибку использования, о которой я могу думать.

(выделено мной)

Это действительно не имеет значения, вы используете ArgumentException или InvalidOperationException. Выберите один, но убедитесь, что он имеет ясный Message.

+1

Thank вы, это определенно попадает в гвоздь на голове. Как я уже упоминал в своем вопросе (который был правильно опровергнут BJ M yers), я думал, что исключение может быть результатом действия пользователя, но это было неправильно. Учитывая, что это проблема разработчика, это определенно ошибка использования. –

+1

Спасибо за крик. FYI: используйте одно из исключений аргументов, если проблема в том, что аргумент неверен. Используйте недопустимое исключение операции, если * текущее состояние объекта не позволяет выполнить желаемую операцию *. Например, если у вас есть объект, представляющий закрытый канал, и вы пытаетесь записать его в трубу, это недопустимая операция, учитывая состояние объекта. –

+0

@EricLippert Конечно, но вот что. Сначала вы установите свойство «не раньше». Затем вы устанавливаете свойство «not after», и они несовместимы. Это из-за значения, которое вы пытаетесь установить для свойства «не после», или из-за состояния, в котором находится объект (поскольку вы сначала задали свойство «не раньше»)? –

9

Я согласен с принятым ответом; Я бы добавил, что если ваш код помещает вашего звонящего в такое положение, в котором должен поймать исключение, чтобы определить, действительно ли предоставленные пользователем данные действительны, то вы сделали то, что я называю «неприятным исключением». Досадно, что вы должны сделать обработчик исключений для обработки не исключительной ситуации. Пользователи, вводящие несогласованные диапазоны дат, не являются исключительными. Это нормальная часть рабочего процесса программы.

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

+0

Согласен. На самом деле, мне было интересно, что эта ситуация должна быть вообще-то. Конечно, запрос, который говорит «не до Феврала 1, а не после 1 января», ничего не вернет, но является ли это ошибкой? Возможно, это должно быть просто предупреждением в пользовательском интерфейсе или даже лучше, как вы указываете, пользовательский интерфейс должен помешать ситуации. –

+0

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

+0

@ rory.ap: Это хорошая идея. В основном это подход, который вы должны предпринять в любом сценарии клиент-сервер: клиент должен отправлять только действительные запросы, но * сервер все еще должен их проверить *. Клиент может быть ошибочным или враждебным. –

Смежные вопросы