Вот два разумных примера того, о чем я думаю, вы говорите. Они иллюстрируют то, что я пытался описать в комментариях, а также то, что описывает @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;
}
}