Поймать несколько исключений одновременно? - PullRequest
1901 голосов
/ 26 сентября 2008

Не рекомендуется просто ловить System.Exception. Вместо этого должны быть обнаружены только «известные» исключения.

Теперь это иногда приводит к ненужному повторяющемуся коду, например:

try
{
    WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
    WebId = Guid.Empty;
}
catch (OverflowException)
{
    WebId = Guid.Empty;
}

Интересно: есть ли способ перехватить оба исключения и вызвать WebId = Guid.Empty только один раз?

Данный пример довольно прост, так как это всего лишь GUID. Но представьте себе код, в котором вы несколько раз модифицируете объект, и если одна из манипуляций не удалась ожидаемым образом, вы хотите «сбросить» object. Однако, если есть непредвиденное исключение, я все еще хочу бросить это выше.

Ответы [ 28 ]

6 голосов
/ 22 сентября 2016

То есть вы повторяете много кода в каждом переключателе исключений? Похоже, что извлечение метода было бы идеей бога, не так ли?

Итак, ваш код сводится к следующему:

MyClass instance;
try { instance = ... }
catch(Exception1 e) { Reset(instance); }
catch(Exception2 e) { Reset(instance); }
catch(Exception) { throw; }

void Reset(MyClass instance) { /* reset the state of the instance */ }

Интересно, почему никто не заметил это дублирование кода.

Начиная с C # 6, у вас есть фильтры исключений , как уже упоминалось другими Таким образом, вы можете изменить код выше к этому:

try { ... }
catch(Exception e) when(e is Exception1 || e is Exception2)
{ 
    Reset(instance); 
}
4 голосов
/ 16 апреля 2017

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

Например, если вы используете исключение «catch-all» в качестве Exception , оно будет предшествовать всем остальным операторам catch, и вы, очевидно, получите ошибки компилятора, однако, если вы измените порядок, вы можете связать свои выражения catch (немного анти-паттерна, я думаю), вы можете поместить тип catch-all Exception внизу, и это будет захватывать любые исключения, которые не учитывались выше в вашем блоке try..catch :

            try
            {
                // do some work here
            }
            catch (WebException ex)
            {
                // catch a web excpetion
            }
            catch (ArgumentException ex)
            {
                // do some stuff
            }
            catch (Exception ex)
            {
                // you should really surface your errors but this is for example only
                throw new Exception("An error occurred: " + ex.Message);
            }

Я настоятельно рекомендую людям просмотреть этот документ MSDN:

Иерархия исключений

4 голосов
/ 23 января 2018

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

например:.

try
{
    // ...
}
catch (FormatException)
{
    DoSomething();
}
catch (OverflowException)
{
    DoSomething();
}

// ...

private void DoSomething()
{
    // ...
}

Как бы я это ни делал, пытаясь найти простой, красивый шаблон

1 голос
/ 26 сентября 2008

Обратите внимание, что я нашел один способ сделать это, но это больше похоже на материал для The Daily WTF :

catch (Exception ex)
{
    switch (ex.GetType().Name)
    {
        case "System.FormatException":
        case "System.OverflowException":
            WebId = Guid.Empty;
            break;
        default:
            throw;
    }
}
0 голосов
/ 27 мая 2019

Я хочу предложить кратчайший ответ (еще один функциональный стиль ):

        Catch<FormatException, OverflowException>(() =>
            {
                WebId = new Guid(queryString["web"]);
            },
            exception =>
            {
                WebId = Guid.Empty;
            });

Для этого вам нужно создать несколько перегрузок метода «Catch», аналогично System.Action:

    [DebuggerNonUserCode]
    public static void Catch<TException1, TException2>(Action tryBlock,
        Action<Exception> catchBlock)
    {
        CatchMany(tryBlock, catchBlock, typeof(TException1), typeof(TException2));
    }

    [DebuggerNonUserCode]
    public static void Catch<TException1, TException2, TException3>(Action tryBlock,
        Action<Exception> catchBlock)
    {
        CatchMany(tryBlock, catchBlock, typeof(TException1), typeof(TException2), typeof(TException3));
    }

и так далее сколько угодно. Но вам нужно сделать это один раз, и вы можете использовать его во всех своих проектах (или, если вы создали пакет nuget, мы могли бы использовать его тоже).

И реализация CatchMany:

    [DebuggerNonUserCode]
    public static void CatchMany(Action tryBlock, Action<Exception> catchBlock,
        params Type[] exceptionTypes)
    {
        try
        {
            tryBlock();
        }
        catch (Exception exception)
        {
            if (exceptionTypes.Contains(exception.GetType())) catchBlock(exception);
            else throw;
        }
    }

p.s. Я не ставил нулевые проверки для простоты кода, рассмотрите возможность добавления проверки параметров.

p.s.2 Если вы хотите вернуть значение из catch, необходимо выполнить те же методы Catch, но с параметрами Return и Func вместо Action.

0 голосов
/ 20 мая 2015

В c # 6.0 Фильтры исключений - улучшения для обработки исключений

try
{
    DoSomeHttpRequest();
}
catch (System.Web.HttpException e)
{
    switch (e.GetHttpCode())
    {
        case 400:
            WriteLine("Bad Request");
        case 500:
            WriteLine("Internal Server Error");
        default:
            WriteLine("Generic Error");
    }
}
0 голосов
/ 07 декабря 2018

Стоит упомянуть здесь. Вы можете ответить на несколько комбинаций (Exception error и exception.message).

Я столкнулся с сценарием сценария использования при попытке привести управляющий объект в сетку данных с содержимым типа TextBox, TextBlock или CheckBox. В этом случае возвращенное исключение было таким же, но сообщение изменилось.

try
{
 //do something
}
catch (Exception ex) when (ex.Message.Equals("the_error_message1_here"))
{
//do whatever you like
} 
catch (Exception ex) when (ex.Message.Equals("the_error_message2_here"))
{
//do whatever you like
} 
0 голосов
/ 29 июля 2016

Просто позвоните попробуйте и поймать дважды.

try
{
    WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
    WebId = Guid.Empty;
}
try
{
    WebId = new Guid(queryString["web"]);
}
catch (OverflowException)
{
    WebId = Guid.Empty;
}

Просто так просто !!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...