Ловля исключений - PullRequest
       18

Ловля исключений

3 голосов
/ 01 декабря 2011

В следующем фрагменте кода задокументирован конструктор new, который генерирует семь различных типов исключений, включая System.IO.PathTooLongException и System.ArgumentException, System.UnauthorizedAccessException и System.SecurityException:

try
{
    var fileInfo = new FileInfo(path);
}
catch ???

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

Итак, вопрос:

Книги и руководства по кодированию говорят мне, что мне не следует использовать catch (Exception) конструкцию, , но я сталкиваюсь со следующей ситуацией - я могу перехватывать и обрабатывать 4 (из 7) типов исключений и их обработка для всех типов исключений абсолютно одинакова.

Как это сделать?


Я также могу подумать о следующем решении, но оно все равно выглядит плохо:

catch (Exception exception)
{
    Debug.Assert(exception is PathTooLongException || exception is ...);

    // (or maybe rethrow it further if there is a type mismatch)

    //... Handling code ...
}

Ответы [ 4 ]

2 голосов
/ 01 декабря 2011

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

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

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

Для этого исключения FileInfo это зависит от того, насколько глубоко он находится в этом стеке. Если это библиотека, в которую можно попасть по нескольким путям и сценариям, вы не должны обращаться с этим, что вы собираетесь делать в этот момент? Если это также так, и он проходит весь путь через глубокий стек к графическому интерфейсу, выполняющему операцию, в которой вы хотите его обработать, что вы собираетесь поймать? Каждое возможное исключение каждого пути кода на его пути выполнения? И, по мере изменения кода, вы собираетесь пересмотреть все пути? В неглубоком пути кода (диалоговое окно информации о файле, которое вызывает этот метод) это простой вызов, но даже в этом случае вы не будете обрабатывать его иначе - вы будете отображать диалоговое окно с сообщением об ошибке или сообщение на панели. Типы исключений предлагают возможность обрабатывать по-разному . В обоих случаях вы обрабатываете исключение, поэтому я говорю «ба хум баг» к этому руководству.

Что очень ясно, вы не должны бросать Исключение типа . Это короткое замыкание способность обрабатывать по-разному.

Еще один связанный пост:

Попытка понять исключения в C #

2 голосов
/ 01 декабря 2011

Кроме того, вы можете сначала проверить путь с помощью File.Exists (путь) или Directory.Exists (путь)

1 голос
/ 10 января 2013

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

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

Если слои хорошо спроектированы и имеют определенные обязанности, то информация об ошибке имеет различное значение, поскольку она всплывает. <-это ключ к тому, что делать, универсального правила не существует. </p>

Итак, это означает, что когда возникает исключение, у вас есть 2 варианта, но вам нужно понять, где в слое вы находитесь:

A) Если вы находитесь в середине уровня, и вы просто внутренняя, обычно частная, вспомогательная функция и что-то идет не так: НЕ БЕСПОКОЙСТВУЙТЕ, пусть вызывающая сторона получит исключение. Это совершенно нормально, потому что у вас нет бизнес-контекста и 1) Вы не игнорируете ошибку и 2) Вызывающий объект является частью вашего слоя и должен был знать, что это может произойти, но теперь вы можете не узнать контекст для его обработки ниже.

или ...

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

Сила приложения - это уровень развязки между слоями. Здесь вы остановите все как общее правило и сбросите ошибку с общим исключением, переводя информацию в более значимую ошибку для верхнего уровня.

ПРАВИЛО: Все точки входа в слой должны быть защищены CATCH ALL, а все ошибки переведены или обработаны. Теперь это происходит только в 1% случаев, в основном вам просто нужно (или можно) вернуть ошибку в правильной абстракции.

Нет, я уверен, что это очень трудно понять. реальный пример ->

У меня есть пакет, который запускает некоторые симуляции. Эти симуляции в текстовых скриптах. есть пакет, который компилирует эти сценарии, и есть универсальный пакет утилит, который просто читает текстовые файлы и, конечно, базовый java RTL. UML-зависимость ->

Симулятор-> Компилятор-> utilsTextLoader-> Файл Java

1) Если что-то ломается в загрузчике утилит в одном приватном файле, и я получаю FileNotFound, Permissions или что-то еще, просто позвольте этому пройти. Больше ничего не поделаешь.

2) На границе, в первоначально вызванной функции utilsTextLoader вы будете следовать приведенному выше правилу и CATCH_ALL. Компилятору все равно, что произойдет, просто нужно сейчас загрузить файл или нет. Таким образом, в подвохе повторно выведите новое исключение и переведите FileNotFound или что-либо еще в «Не удалось прочитать файл XXXX».

3) Компилятор теперь будет знать, что источник не был загружен. Это ВСЕ, что нужно знать. Поэтому, если я позже изменю utilsTestLoader для загрузки из сети, компилятор не изменится. Если вы отпустите FileNotFound и позже измените его, вы окажете влияние на компилятор даром.

4) Цикл повторяется: фактическая функция, которая вызвала нижний уровень для файла, ничего не сделает при получении исключения. Так что это позволяет ему подняться.

5) Как исключение попадает на слой между симулятором и компилятором, компилятор снова CATCHES_ALL, скрывая любые детали и просто выдает более конкретную ошибку: «Не удалось скомпилировать скрипт XXX»

6) Наконец, повторите цикл еще раз, функция симулятора, которая вызывает компилятор, просто отпускает.

7) Наконец, граница для пользователя. Пользователь это СЛОЙ и все относится. У основного есть попытка, которая делает catches_ALL и, наконец, просто создает красивое диалоговое окно или страницу и «выдает» переведенную ошибку пользователю.

Так видит пользователь.


Симулятор: фатальная ошибка не может запустить симулятор

-Compiler: не удалось скомпилировать скрипт FOO1

- TextLoader: не удалось прочитать файл foo1.scp

--- trl: FileNotFound


Сравнить с:

a) Компилятор: исключение NullPointer <- общий случай и потерянная ночь отладки опечатки имени файла </p>

b) Загрузчик: файл не найден <- Я упоминал, что загрузчик загружает сотни сценариев ?? </p>

или

в) Ничего не происходит, потому что все было проигнорировано !!!

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

Ну, мои 2ct. Эти простые правила много раз спасали мою жизнь ...

-Ale

0 голосов
/ 01 декабря 2011

Вы можете сделать что-то вроде этого:

try
{
    var fileInfo = new FileInfo(path);
}
catch (System.IO.PathTooLongException ex)
{
    handleError(ex);
}
catch (System.ArgumentException ex)
{
   handleError(ex);
}
catch (System.UnauthorizedAccessException ex)
{
}
catch (System.SecurityException ex)
{
   handleError(ex);
}

public void handleError(Exception ex)
{
    //do some stuff
}
...