Подтвердить что ты не робот

Обработка исключений - это хороший способ?

Мы боремся с политикой, чтобы правильно обрабатывать исключения в нашем приложении. Здесь наши цели для него (обобщены):

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

Мы вышли с решением, которое включает в себя общее исключение приложения и работает как это в куске кода:

try {
  // Do whatever
}
catch(ArgumentNullException ane)
{
  // Handle, optinally log and continue
}
catch(AppSpecificException)
{
  // Rethrow, don't log, don't do anything else
  throw;
}
catch(Exception e)
{
  // Log, encapsulate (so that it won't be logged again) and throw
  Logger.Log("Really bad thing", e.Message, e);
  throw new AppSpecificException(e)
}

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

У меня не так много опыта с шаблонами обработки исключений... Является ли это хорошим способом решения наших задач? Имеются ли какие-либо серьезные недостатки или большие красные предупреждения?

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

Не регистрируйте исключение, а затем повторно бросайте его - ответственность за обработку вызовов/регистрацию всех вызываемых вами исключений лежит на вызывающих пользователях.

Ухватите только исключение для его обработки (например, для его регистрации) или добавьте контекстную информацию.

Ответ 3

Это довольно распространенный подход для решения проблемы обработки исключений (от более конкретных до менее конкретных).

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

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

Ответ 4

Первая опция для решения проблемы трассировки стека:

class AppSpecificException : ApplicationException
{
    public string SpecificTrace { get; private set; }
    public string SpecificMessage { get; private set; }

    public AppSpecificException(string message, Exception innerException)
    {
        SpecificMessage = message;
        SpecificTrace = innerException.StackTrace;
    }

}

Мне нужно было написать пример, чтобы понять вопрос и проверить проблему stacktrace, это код для меня, обратить внимание на метод button2_click, в конце концов, в моем текстовом поле отображаются строка аварийной остановки и stacktrace:

    private String internalValue;

    private void Operation1(String pField)
    {
        if (pField == null) throw new ArgumentNullException("pField");
        internalValue = pField;
    }

    private void Operation2(Object pField)
    {
        if (pField == null) throw new ArgumentNullException("pField");
        internalValue = Convert.ToInt32(pField).ToString();
    }

    private void Operation3(String pField)
    {
        if (pField == null) throw new ArgumentNullException("pField");
        internalValue = pField;
        Operation2(-1);
    }


    /// <exception cref="AppSpecificException"><c>AppSpecificException</c>.</exception>
    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            Operation1("One");
            Operation2("Two");
            Operation3("Three");
            MessageBox.Show(internalValue);
        }
        catch (ArgumentNullException ex)
        {
            textBoxException.Text = ex.Message + (char) 13 + (char) 10 + ex.StackTrace;
        }
        catch (AppSpecificException ex)
        {
            //textBoxException.Text = ex.Message + (char)13 + (char)10 + ex.StackTrace;
            throw;
        }
        catch (Exception ex)
        {
            textBoxException.Text = ex.Message + (char)13 + (char)10 + ex.StackTrace;                    
            throw new AppSpecificException("crash", ex);
        }

    }

    private void button2_Click(object sender, EventArgs e)
    {
        try
        {
            button1_Click(sender, e);
        }
        catch (AppSpecificException ex)
        {
            textBoxException.Text = ex.SpecificMessage + (char) 13 + (char) 10 + ex.SpecificTrace;
        }
    }

Ответ 5

Старайтесь избегать создания нового исключения и реорганизации, так как бросание исключения задает трассировку стека, где было выбрано исключение. Просто сделайте простой бросок. См. Слишком много повторного использования в блоге Eric Lippert.

Ответ 6

Я бы рекомендовал больше подумать о том, какие шаблоны вы хотите использовать для "раздачи"

Если ваши шаблоны обработки сводятся к логарифму или реверту, тогда вновь занесенная ошибка будет зарегистрирована. Поэтому, в конце концов, это просто регистрация ошибок. Если вы используете ASP.NET, используйте elmah, поэтому, по крайней мере, ваш код не покрывается плитой котла try/catch-and-log.

Есть только несколько способов "обрабатывать" ошибки, которые не заканчиваются простым протоколированием.

Re-попробовать. (Следите за бесконечными циклами)

Подождите и повторите попытку.

Попробуйте использовать другую, но эквивалентную технику (не удается подключиться к http? попробуйте подключиться на https).

Установите отсутствующие условия (создайте папку, в которой было выбрано FolderNotFoundException)

Игнорируйте ошибку - подумайте дважды об этом, это имеет смысл только тогда, когда ошибка не является действительно проблемой, например, если сторонняя библиотека предупреждает вас о состоянии, которое не применяется.

Ответ 7

Хорошим решением об обработке исключений является использование перехвата. Однако вы должны проверить, может ли этот шаблон применяться к вашему приложению в зависимости от архитектуры: для перехвата требуется контейнер.

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

Обратите внимание, что вы можете добавить try catch в методы для управления определенным исключением, которые неуправляемы в ваших перехватчиках.

Перехват единства: http://msdn.microsoft.com/en-us/library/dd140045.aspx