Необработанное исключение с помощью команды "выбросить новое ...", какова лучшая практика?Это уже обработано - PullRequest
2 голосов
/ 14 сентября 2011

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

Работа должна быть выполнена с новым классом, который наследует объект Exception и расширяет функциональность новым "выходом", который состоит из сигнала ошибки для пользователя и подпрограммы регистрации.

Возможно, мне нужно лучше понять использование throw, но я хотя бы смог сделать его достаточно прозрачным, например:

public SomeObject GetVersion(byte p)
{
    switch ((SomeObject)p)
    {
        case Version.SomeType1:
            ...
            break;
        case Version.SomeType2:
            ...
            break;
        default:
            throw new UnexpectedQueryException(this.someOtherObject, errorCode);
    }
    return (SomeObject)p;
}

Я думаю, вы можете увидеть, что я пытаюсь сделать здесь,

Я пытаюсь выбросить, когда приложение не может обработать запрос.Бросок предназначен для выполнения выполнения через исключение (которое генерирует адекватный код ошибки для вызывающей стороны).Этот пример является ошибкой типа «Я знаю, что вы дали мне 9, но здесь разрешено только 1-8)», который errorCode отправляет дальше UnexpectedQueryException(...).

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

На мой взгляд, это очень хорошо обрабатывается.

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

Также я, конечно, хочу, чтобы приложение продолжало работать.

Часть кода из логики исключения,

public class UnexpectedQueryException: CommunicationException
{
    public UnexpectedQueryException(SomeObject object, ErrorCode errorCode) : base("UnexpectedQueryException", object, errorCode)
    {
     .........
    }
}

, которая, в свою очередь, наследует базовый объект исключения,

public class CommunicationException : Exception
{
    ..some fields..

    public CommunicationException(string Message, SomeObject object, ErrorCode errorcode)
    {
     .....
    }
    public CommunicationException() : base("CommunicationException")
    { }
}

Ответы [ 4 ]

6 голосов
/ 14 сентября 2011

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

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

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

try
{
  // code that can throw 
}
catch(VerySpecificException ex)
{
  // communicate to user details about VerySpecificException. 
  // possibly log.
  // Do not re-throw or throw a new excpetion as it is now handled. 
}
catch(AnotherSpecificException ex)
{
  // communicate to user details about AnotherSpecificException. 
}
catch(LessSpecificException ex)
{
  // communicate to user details about LessSpecificException. 
}
catch(EveLessSpecificException ex)
{
  // communicate to user details about EvenLessSpecificException. 
}
3 голосов
/ 14 сентября 2011

Вы должны понимать, как и когда отлавливать исключения.

Самое неприятное при добавлении исключений в (рабочий) поток состоит в том, что любой обработчик исключений верхнего уровня (такой как try / catch в program.cs).) не будет ловить и регистрировать исключения, созданные в потоках.Следовательно, у вас всегда должен быть общий try / catch в методе ввода потока, по крайней мере, если вы не хотите, чтобы ваше приложение умирало.

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

Чтобы лучше понять исключения, вы можете прочитать статьи моего блога об исключениях: http://blog.gauffin.org/tag/exceptions/

1 голос
/ 14 сентября 2011

A throw не обрабатывает ошибку, но вызывает ее. Без throw ошибка не обрабатывается.

Вы обрабатываете исключение, перехватывая его. Вам нужен блок try - catch где-то в вашем коде, который вызывает GetVersion (или где-то в коде, который вызывает код, который вызывает GetVersion и т. Д.). Если вы не уловите UnexpectedQueryException в иерархии вызовов, он не будет обработан, и ваше приложение остановится.

Пример, который вызывает GetVersion разное время (без обработки исключений).

List<SomeObject> GetAllVersions(byte[] bytes)
{
    var result = new List<SomeObject>();

    foreach (byte b in bytes)
    {
        result.Add(GetVersion(b));
    }

    return result;
}

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

foreach (byte b in bytes)
{
    try
    {
        result.Add(GetVersion(b));
    }
    catch (UnexpectedQueryException e)
    {
        // this is where your exception handling starts
        // display an error, log the exception, ...
    }
}

Или вы можете обработать исключение на другом уровне вашего приложения, например, обернуть вызов на GetAllVersions в try-catch блок:

List<SomeObject> = null;
try
{
    versionList = GetAllVersions(bytes)
    // do something with versionList
}
catch (UnexpectedQueryException e)
{
    // this is where your exception handling starts
    // display an error, log the exception, ...
    // Note that versionList will be null in error case
}

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

0 голосов
/ 14 сентября 2011

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

Код, который вы предоставили, всегда будет вызывать исключение, потому что вы пытаетесь преобразовать тип значения типа byte к ссылочному типу типа SomeObj :

public SomeObject GetVersion(byte p)
{
    switch ((SomeObject)p)
    {
        case Version.SomeType1:
            ...
            break;
        case Version.SomeType2:
            ...
            break;
        default:
            throw new UnexpectedQueryException(this.someOtherObject, errorCode);
    }
    return (SomeObject)p;
}
...