Обработка исключений в пользовательском классе - PullRequest
1 голос
/ 23 февраля 2012

У меня есть класс с приватным полем Dictionary<string, T> (users), где ключ string представляет имя пользователя. Я написал несколько методов для этого класса, например, метод GetValue(string userid) возвращает объект T, который связан с указанным именем пользователя.

Я бы обработал исключения, которые могут возникнуть в этом классе и которые вызваны словарем. Например:

  • если указанный ключ имеет значение null, Dictionary выдает ArgumentNullException;
  • если указанный ключ не существует в Dictionary, он выдает KeyNotFoundException.

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

public T GetValue(string userid)
{
    try
    {
        return users[userid];
    }
    catch(ArgumentNullException ex1)
    {
        // re-throw the same exception
    }
    catch(KeyNotFoundException ex2)
    {
        throw new UserIdNotFoundException("The specified userid does not exist.", ex2);   // custom exception
    }
}

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

public T GetValue(string userid)
{
    if (userid != null)
    {
        if(users.ContainsKey(userid))
            return users[userid];
        else throw new UserIdNotFoundException("The specified userid does not exist.", ex2);   // custom exception
    }
    else throw new ArgumentNullException(...);
}

Третий подход аналогичен второму, но он использует TryGetValue метод Dictionary.

public T GetValue(string userid)
{
    if (userid != null)
    {
        T value;
        if(users.TryGetValue(userid, out value))
            return value;
        else throw new UserIdNotFoundException("The specified userid does not exist.", ex2);   // custom exception
    }
    else throw new ArgumentNullException(...);
}

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

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

В моем случае метод GetValue(string userid) будет вызываться редко, но потенциальные пользователи класса могут использовать его очень часто.

Ответы [ 4 ]

2 голосов
/ 23 февраля 2012

Это зависит от цели вашего класса.Например, если ваш класс должен выступать в качестве оболочки-словаря, клиентам было бы полезно распространять аналогичное поведение ошибки / исключения, типичное Dictionary.Если ваш класс реализует что-то более сложное (скорее всего), я бы сказал, что вам лучше представлять свои ошибки вызывающей стороне.Что касается того, какой подход выбрать, выполните ту же проверку ввода, что и при обычном Dictionary взаимодействии.Другими словами, если вы обычно проверяете ContainsKey или TryGetValue перед добавлением к Dictionary, продолжайте делать это здесь, но тогда нет необходимости создавать новое исключение.Вместо этого сообщите об ошибке вызывающей стороне в терминах, которые они могут понять.Они не должны знать, что вы используете Dictionary под капотом.

2 голосов
/ 23 февраля 2012

Когда есть практичный и эффективный способ избежать исключения в базовом типе данных, это, вероятно, хорошая идея, даже если вы в конечном итоге создадите исключение самостоятельно.Использование TryGetValue почти всегда является правильным способом извлечения чего-либо из словаря, который может содержать или не содержать определенный элемент.

Кроме того, ваш внутренний метод вызывает throw исключения, и вы знаете, что они означают, это частолучше всего обернуть их в свои собственные исключения, если вы не уверены, что все такие исключения всегда будут иметь одно и то же семантическое значение всякий раз, когда они встречаются в коде, который вы вызываете.В противном случае, предположим, что при попытке добавить дублирующего пользователя словарь выбрасывает ArgumentException.Если вы позволите этому фильтруться как ArgumentException вместо того, чтобы обернуть его как что-то еще, и позже для кода где-то внутри вашего AddUser метода станет возможным выбросить ArgumentException для чего-то еще, вам может быть трудночтобы помочь вашему абоненту отличить ArgumentException, вызванный дублирующимся пользователем, от ArgumentException, который возникает по какой-то другой причине.

2 голосов
/ 23 февраля 2012

ContainsKey и TryGetValue оба метода могут избежать броска KeyNotFoundException

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

Подход

TryGetValue проще в использовании, чем подход ContainsKey, но только если вы хотите проверить ключ в коллекции и также хотите получить значение, связанное с ним. Если вы хотите только проверить, присутствует ли ключ или нет, используйте только ContainsKey.

Подробнее: Объект словаря (ContainsKey Vs. TryGetValue) может помочь вам.

0 голосов
/ 23 февраля 2012

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

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

Самая худшая реализация first :

  • Он не является функционально эквивалентным в случае, если аргумент равен нулю.
  • Он получает снижение производительности из оператора try - компилятору, очевидно, придется настраивать некоторые данные в стеке.
  • Существует также проблема стиля, на мой взгляд, с программами, которые широко используют catch операторов. Лучшее, что можно сделать с исключениями, - это дать им всплыть, пока они не будут зарегистрированы, или что-то с ними можно сделать.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...