Перехват исключений по базовому классу
От: FrozenHeart  
Дата: 20.08.15 09:04
Оценка:
Приветствую.

Почему все настолько плохо относятся к практике перехвата исключений по базовому классу?

Вот, что я имею ввиду:

try
{
  DoSmth();
}
catch (Exception ex)
{
  Console.WriteLine(ex.Message);
}


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

Рассмотрим пример.

Мне необходимо вызвать метод ZipFile.CreateFromDirectory. Смотрим, что он может выбросить:

ArgumentException
ArgumentNullException
PathTooLongException
DirectoryNotFoundException
IOException
UnauthorizedAccessException
NotSupportedException


Допустим, валидность аргументов я буду проверять перед вызовом данного метода самостоятельно, так что первые три типа исключений (ArgumentException, ArgumentNullException и PathTooLongException) сразу же отпадают. Существование директории лучше не проверять предварительно, ведь в общем случае добиться атомарности в данном случае всё равно не получится:

if (Directory.Exists(path))
{
  // Директория удаляется
  ZipFile.CreateFromDirectory(path, "some.zip"); // Выбрасывается исключение из-за отсутствия sourceDirectory
}


Остальные типы исключений (IOException, UnauthorizedAccessException и NotSupportedException) также могут возникнуть из-за каких-то внешних обстоятельств, проверять которые заранее мы либо запаримся, либо просто не сможем атомарно, как в предыдущем случае.

Теперь представьте (и в моём случае это вполне частая задача), что реагировать на все типы исключений мне необходимо одним и тем же образом (например, писать текст исключения в лог и завершать выполнение текущего метода). Чем в таком случае плох принцип перехвата исключений по базовому классу (в данном случае Exception)?

Подливают масла в огонь ещё и third-party libraries, по документации которых (если она вообще есть) далеко не всегда понятно, какие именно типы исключений какие методы выбрасывают. Лезть в реализацию? Во-первых, она на всегда доступна, а, во-вторых, надеяться на такую информацию, я считаю, не стоит. Проще уж ловить Exception.

Ещё один момент. Что если разработчики используемой Вами библиотеки / фреймворка решат добавить с новой версией дополнительные типы исключений? Например, было исключение NotSupportedException, которое возникало по двум следующим причинам:

NotSupportedException

sourceDirectoryName or destinationArchiveFileName contains an invalid format.

-or-

The zip archive does not support writing.


А теперь представьте, что его "разбили" на два типа -- InvalidFormatException и ZipArchiveDoesNotSupportWritingException. И это хорошо, если они оба будут наследоваться от NotSupportedException! А что, если нет? Читать changelon? А что, если упустите эту информацию из виду? Писать юнит-тесты? Это тоже не идеальный инструмент, т.к. их составляют люди, и они вполне могут забыть проверить какую-то определённую ситуацию.

Единственная проблема, которая мне приходит на ум -- это возможный перехват "лишних" исключений (например, перехват нажатия Ctrl-C или отмены таска), но для таких случаев многие библиотеки и фреймворки специально создают отдельную иерархию классов, которая начинается не с Exception.

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