есть ли способ поймать оригинальное исключение, если во время обработки возникнет другое исключение, такое как C#? - PullRequest
0 голосов
/ 27 февраля 2020

предположим, что мы имеем следующий код в C#:

try{
  ....
  try{

    throw new Exception1("exception1");

  }catch(Exception exception){

     ...
    throw new Exception2("exception2");

  }
}catch(Exception exception){
    ...
    log(exception.message);
}

Возможно ли в точке регистрации (внешнем перехвате) получить доступ к объекту exception1 и также зарегистрировать этот объект?

1 Ответ

0 голосов
/ 29 февраля 2020

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

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

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

Но другое место в том, что если я пытаюсь выполнить операцию, и она выдает (я не проверял, что File.ReadAllLines на самом деле выдает IOException, но я предполагаю, что это возможно). В этом случае я не хочу обременять своих пользователей отловом возможного IOException, вместо этого я перевел его в ApplicationException, который я документирую. Я обертываю IOException ловушкой и броском моего ApplicationException, но я включаю IOException как внутреннее исключение , чтобы отладка и отслеживание других проблем работали. Код выглядит следующим образом:

public IEnumerable<string> AccessFile(string pathName)
{
    if (string.IsNullOrEmpty(pathName) || !IsValidFileName(pathName))
    {
        throw new ApplicationException("Invalid Path Name");
    }

    try
    {
        var result = File.ReadAllLines(pathName);
        return result;
    }
    catch (IOException ex)
    {
        throw new ApplicationException("Error Accessing File", ex);
    }
}

Это второй параметр ApplicationException, который устанавливает внутреннее исключение. Этот шаблон очень общий.


Другой пример - то, что описывает @Jonesopolis.

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

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

Это типичный код, о котором я говорю. Это также очень общий шаблон:

public void DoSomethingImportant()
{
    try
    {
        DoSomethingLowLevel();
    }
    catch (Exception ex)
    {
        GetLogger().Log(ex);
        throw;
    }
}
...