Зачем ловить и отбрасывать исключение в C #? - PullRequest
507 голосов
/ 19 мая 2009

Я смотрю на статью C # - Объект передачи данных о сериализуемых DTO.

Статья включает в себя этот кусок кода:

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    }
    catch(Exception ex) {
        throw ex;
    }
}

Остальная часть статьи выглядит вменяемой и разумной (нубу), но этот try-catch-throw вызывает WtfException ... Разве это не эквивалентно тому, что вообще не обрабатывается исключения?

Ergo:

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

Или я упускаю что-то фундаментальное в обработке ошибок в C #? Это почти так же, как Java (за исключением проверенных исключений), не так ли? ... То есть они оба усовершенствовали C ++.

Вопрос переполнения стека Разница между перебрасыванием улова без параметров и бездействием? , кажется, подтверждает мое утверждение о том, что try-catch-throw-no- соч.


EDIT:

Просто подведу итог всем, кто найдет эту ветку в будущем ...

НЕ

try {
    // Do stuff that might throw an exception
}
catch (Exception e) {
    throw e; // This destroys the strack trace information!
}

Информация трассировки стека может иметь решающее значение для определения основной причины проблемы!

DO

try {
    // Do stuff that might throw an exception
}
catch (SqlException e) {
    // Log it
    if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
        // Do special cleanup, like maybe closing the "dirty" database connection.
        throw; // This preserves the stack trace
    }
}
catch (IOException e) {
    // Log it
    throw;
}
catch (Exception e) {
    // Log it
    throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
    // Normal clean goes here (like closing open files).
}

Поймайте более конкретные исключения, прежде чем менее конкретные (как в Java).


Ссылка:

Ответы [ 16 ]

3 голосов
/ 30 июля 2009

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

3 голосов
/ 19 мая 2009

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

Вы можете сказать Catch io.FileNotFoundExeption ex, а затем использовать альтернативный путь к файлу или что-то подобное, но все равно выдаете ошибку.

Также выполнение Throw вместо Throw Ex позволяет сохранить полную трассировку стека. Throw ex перезапускает трассировку стека из оператора throw (надеюсь, это имеет смысл).

2 голосов
/ 19 мая 2009

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

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

Чтобы повторить, хотя нет смысла поймать исключение в приведенном вами примере. НЕ делай так!

1 голос
/ 26 декабря 2012

Большинство ответов говорят о сценарии catch-log-rethrow.

Вместо написания этого в вашем коде рассмотрите возможность использования AOP, в частности Postsharp.Diagnostic.Toolkit с OnExceptionOptions IncludeParameterValue и IncludeThisArgument

1 голос
/ 22 сентября 2009

В дополнение к тому, что сказали другие, см. мой ответ на связанный вопрос, который показывает, что перехват и перебрасывание не запрещены (это в VB, но часть кода может быть C # вызывается из VB).

1 голос
/ 16 сентября 2009

Извините, но многие примеры "улучшенного дизайна" до сих пор ужасно пахнут или могут вводить в заблуждение. Попробовав {} catch {log; throw} просто совершенно бессмысленно. Регистрация исключений должна выполняться в центральном месте внутри приложения. в любом случае исключения заполняют трассировку стека, почему бы не записать их где-нибудь вверх и близко к границам системы?

Следует соблюдать осторожность при сериализации вашего контекста (т. Е. DTO в одном конкретном примере) только в сообщении журнала. Он может легко содержать конфиденциальную информацию, которая может не захотеть попасть в руки всех людей, которые могут получить доступ к файлам журнала. И если вы не добавите новую информацию в исключение, я действительно не вижу смысла в исключении. У старой доброй Java есть кое-что для этого, она требует, чтобы вызывающая сторона знала, какие исключения следует ожидать, затем вызывая код. Поскольку у вас этого нет в .NET, упаковка не приносит пользы, по крайней мере, в 80% случаев, которые я видел.

...