28 Вопрос: Поймать несколько исключений одновременно?

вопрос создан в Wed, Oct 18, 2017 12:00 AM

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

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

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

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

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

    
1914
  1. Если вы используете .net 4 и выше, я предпочитаю использовать aggregateexception msdn.microsoft.com/en-us/library/system.aggregateexception.aspx
    2013-10-18 03: 21: 37Z
  2. Bepenfriends - поскольку System.Guid не выбрасывает AggregateException , было бы здорово, если вы (или кто-то другой) мог бы опубликовать ответ, показывающий, как вы бы включили его в AggregateException и т. д.
    2014-01-30 18: 53: 54Z
  3. 2014-08-14 17: 25: 01Z
  4. "Не рекомендуется просто перехватывать System.Exception." -и если метод может генерировать 32 типа исключений, что он делает? написать улов для каждого из них в отдельности?
    2015-05-23 20: 22: 20Z
  5. Сохраняйте все как есть. Переместите код в обработчик ошибок, если хотите, чтобы в операторе catch была только одна строка.
    2017-03-04 03: 03: 53Z
28 ответов                              28                         

Поймай System.Exception и включи типы

 
catch (Exception ex)            
{                
    if (ex is FormatException || ex is OverflowException)
    {
        WebId = Guid.Empty;
        return;
    }

    throw;
}
    
1947
2016-11-26 01: 53: 35Z
  1. К сожалению, FxCop (т. е. Visual Studio Code Analysis) не нравится, когда вы ловите Exception.
    2010-08-27 19: 48: 16Z
  2. Я согласен с тем, что не перехватывается исключение, но в этом случае перехват является фильтром. Вы можете иметь уровень выше, который будет обрабатывать другие типы исключений. Я бы сказал, что это правильно, хотя он включает в себя улов (исключение х). Он не изменяет поток программы, он просто обрабатывает определенные исключения, а затем позволяет остальной части приложения работать с любыми другими типами исключений.
    2011-06-14 19: 13: 51Z
  3. Последняя версия FxCop не выдает исключение при использовании кода выше.
    2011-07-08 05: 12: 06Z
  4. Во-первых, не уверен, что не так с кодом OP. Ответ № 1 принят почти в два раза больше строк и гораздо менее читабелен.
    2012-09-04 21: 57: 49Z
  5. @ JoãoBragança: Хотя в этом ответе в этом примере используется больше строк, попробуйте представить, например, имеете ли вы дело с файловым вводом-выводом, и все, что вам нужно сделать, это перехватить эти исключения и делают некоторые сообщения журнала, но только те, которые вы ожидаете, исходя из вашего файла IO методDS. Тогда вам часто приходится иметь дело с большим количеством (около 5 или более) различных типов исключений. В такой ситуации такой подход может сэкономить вам несколько строк.
    2013-11-28 14: 47: 07Z

РЕДАКТИРОВАТЬ: я согласен с другими, которые говорят, что с C # 6.0 фильтры исключений теперь являются идеальным способом: catch (Exception ex) when (ex is ... || ex is ... )

За исключением того, что я все еще ненавижу однострочный макет и лично выложу код, как показано ниже. Я думаю, что это так же функционально, как и эстетично, так как я считаю, что это улучшает понимание. Некоторые могут не согласиться:

 
catch (Exception ex) when (
    ex is ...
    || ex is ...
    || ex is ...
)

ORIGINAL:

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

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

 
private void TestMethod ()
{
    Action<Exception> errorHandler = ( ex ) => {
        // write to a log, whatever...
    };

    try
    {
        // try some stuff
    }
    catch ( FormatException  ex ) { errorHandler ( ex ); }
    catch ( OverflowException ex ) { errorHandler ( ex ); }
    catch ( ArgumentNullException ex ) { errorHandler ( ex ); }
}

Я не могу не задаться вопросом ( предупреждение : впереди немножко иронии /сарказма), зачем вообще все эти усилия просто заменять следующим:

 
try
{
    // try some stuff
}
catch( FormatException ex ){}
catch( OverflowException ex ){}
catch( ArgumentNullException ex ){}

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

 
// sorta sucks, let's be honest...
try
{
    // try some stuff
}
catch( Exception ex )
{
    if (ex is FormatException ||
        ex is OverflowException ||
        ex is ArgumentNullException)
    {
        // write to a log, whatever...
        return;
    }
    throw;
}

Потому что, конечно, он автоматически не становится более читабельным.

Конечно, я оставил три идентичных экземпляра /* write to a log, whatever... */ return; из первого примера.

Но это как бы моя точка зрения. Вы все слышали о функциях /методах, верно? Шутки в сторону. Напишите общую функцию ErrorHandler и, например, вызывайте ее из каждого блока catch.

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

Фаза обслуживания для тех, кто может быть относительно новичком в программировании, будет составлять 98,7% или более от общего срока службы вашего проекта, и плохое чмо, выполняющее обслуживание, почти наверняка будет кем-то другим, кроме вас. , И есть очень хороший шанс, что они будут тратить 50% своего времени на работу, ругаясь на ваше имя.

И, конечно, FxCop лает на вас, и поэтому вам необходимо также добавить в код атрибут, который имеет точное отношение к работающей программе и имеет только там, чтобы сказать FxCop игнорировать проблему, которая в 99,9% случаев является абсолютно правильной при маркировке. И, извините, я могу ошибаться, но разве этот атрибут «игнорировать» не скомпилирован в ваше приложение?

Поможет ли поместить весь тест if в одну строку, чтобы сделать его более читабельным? Я так не думаю. Я имею в виду, у меня когда-то был другой программист, яростно споривший однажды, что размещение большего количества кода в одной строке заставит его «работать быстрее». Но, конечно, он был совершенно безумным. Попытка объяснить ему (с открытым лицом - что было непросто), как интерпретатор или компилятор разбил бы эту длинную строку на дискретные операторы по одной инструкции на строку - по существу, идентичные результату, если бы он пошел вперед и просто сделал код читабельным вместо того, чтобы пытаться перехитрить компилятор - не оказал на него никакого влияния. Но я отвлекся.

Насколько менее читаемым это становится, когда вы добавляете еще три типа исключений, через месяц или два? (Ответ: он становится много менее читаемым).

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

Просто говорю ...

 
// super sucks...
catch( Exception ex )
{
    if ( ex is FormatException || ex is OverflowException || ex is ArgumentNullException )
    {
        // write to a log, whatever...
        return;
    }
    throw;
}
    
469
2017-02-14 20: 38: 54Z
  1. Когда я впервые наткнулся на этот вопрос, я был во всем принятом ответе. Круто я могу просто поймать все Exception с и проверить тип. Я думал, что это убранокод, но что-то заставляло меня возвращаться к вопросу, и я фактически читал другие ответы на вопрос. Я жевал это некоторое время, но я должен согласиться с вами. более удобнее для чтения и обслуживания, чтобы использовать функцию, чтобы высушить ваш код, чем перехватывать все, проверять сравнение типов по списку, переносу кода и выбрасыванию. Спасибо за опоздание и предоставление альтернативного и вменяемого (IMO) варианта. +1.
    2014-03-06 14: 55: 27Z
  2. Использование функции обработки ошибок не сработает, если вы захотите включить throw;. Вам придется повторять эту строку кода в каждом блоке catch (очевидно, это не конец света, но стоит упомянуть, поскольку этот код необходимо будет повторять).
    2014-06-17 08: 48: 33Z
  3. @ kad81, это правда, но вы все равно получите преимущество написания кода регистрации и очистки в одном месте и его изменения в одном месте, если это необходимо без глупой семантики перехвата базового типа исключения, а затем ветвления на основе типа исключения. И этот дополнительный оператор throw(); в каждом блоке перехвата - это небольшая цена, IMO, и все равно оставляет вам возможность выполнить дополнительную очистку, зависящую от типа исключения, если это необходимо.
    2014-06-18 18: 39: 36Z
  4. Привет @Reitffunk, просто используйте Func<Exception, MyEnumType> вместо Action<Exception>. Это Func<T, Result>, при этом Result является типом возвращаемого значения.
    2015-03-30 16: 42: 12Z
  5. Я полностью согласен здесь. Я тоже прочитал первый ответ, и мысль кажется логичной. Перемещен в общий 1 для всех обработчиков исключений. Что-то внутри меня заставило меня внутренне тошнить ... так что я перевернул код. Потом наткнулся на эту красавицу! Этот должен быть принятым ответом
    2015-09-14 12: 33: 04Z

Как уже отмечали другие, вы можете иметь оператор if внутри блока catch, чтобы определить, что происходит. C # 6 поддерживает фильтры исключений, поэтому будет работать следующее:

 
try { … }
catch (Exception e) when (MyFilter(e))
{
    …
}

Метод MyFilter может выглядеть примерно так:

 
private bool MyFilter(Exception e)
{
  return e is ArgumentNullException || e is FormatException;
}

Кроме того, все это можно сделать встроенным (правая часть оператора when просто должна быть логическим выражением).

 
try { … }
catch (Exception e) when (e is ArgumentNullException || e is FormatException)
{
    …
}

Это отличается от использования оператора if из блока catch, использование фильтров исключений не будет разматывать стек.

Вы можете загрузить Visual Studio 2015 , чтобы проверить это из.

Если вы хотите продолжить использовать Visual Studio 2013, вы можете установить следующий пакет nuget:

  

Install-Package Microsoft.Net.Compilers

На момент написания статьи это будет включать поддержку C # 6.

  

Ссылка на этот пакет приведет к созданию проекта с использованием   конкретная версия компиляторов C # и Visual Basic, содержащихся в   пакет, в отличие от любой версии установленной системы.

    
305
2015-10-06 18: 11: 12Z
  1. Терпеливо жду официального релиза 6 ... Мне бы хотелось, чтобы это получилось, когда это произойдет.
    2015-02-14 13: 41: 32Z
  2. @ RubberDuck Я умираю за нулевой оператор распространения из C # 6. Пытаюсь убедить остальную часть моей команды, что риск нестабильного языка /компилятора того стоит. Множество мелких улучшений с огромным влиянием. Что касается пометки в качестве ответа, это не важно, пока люди понимают, что это будет /возможно, я счастлив.
    2015-02-14 19: 52: 07Z
  3. Верно ?! Я буду внимательно смотреть на мою кодовую базу в ближайшем будущем. =) Я знаю, что проверка не важна, но с учетом принятого ответаr скоро устареет, я надеюсь, что OP вернется, чтобы проверить это, чтобы обеспечить его надлежащую видимость.
    2015-02-14 20: 02: 24Z
  4. Отчасти поэтому я еще и не присудил @Joe. Я хочу, чтобы это было видно. Вы можете добавить пример встроенного фильтра для ясности.
    2015-10-06 16: 15: 57Z

К сожалению, не в C #, поскольку для этого вам понадобится фильтр исключений, а C # не раскрывает эту функцию MSIL. VB.NET имеет такую ​​возможность, например,

 
Catch ex As Exception When TypeOf ex Is FormatException OrElse TypeOf ex Is OverflowException

Что вы можете сделать, это использовать анонимную функцию для инкапсуляции вашего кода ошибки, а затем вызвать его в этих определенных блоках перехвата:

 
Action onError = () => WebId = Guid.Empty;
try
{
    // something
}
catch (FormatException)
{
    onError();
}
catch (OverflowException)
{
    onError();
}
    
185
2008-09-25 21: 03: 57Z
  1. Интересная идея и еще один пример того, что VB.net имеет некоторые интересные преимущества перед C # иногда
    2008-09-25 21: 19: 01Z
  2. @ MichaelStum с таким синтаксисом, который я вряд ли назвал бы интересным вообще ... shudder
    2014-10-09 12: 15: 06Z
  3. Фильтры исключений появятся в c # 6! Обратите внимание на разницу в использовании фильтров в пользу повторного бросания roslyn.codeplex.com/discussions/541301
    2014-11-26 13: 26: 22Z
  4. @ ArneDeruwe Спасибо за эту ссылку! Я только что узнал еще одну важную причину не перебрасывать: throw e; уничтожает стек трассировки и callstack, throw; уничтожает «только» стек вызовов (что делает аварийные дампы бесполезными!) A очень хорошо причина использовать ни один, если этого можно избежать!
    2014-12-11 14: 53: 36Z
  5. Если я не ошибаюсь, вы также можете пропустить ловушку в VB, как вы можете с помощью операторов case или (switch in c #), например Try Catch ex As ArgumentException Catch ex As NullReferenceException End Try Но, к сожалению, C # этого не делает таким образом, у нас остался вспомогательный метод или общий метод определения типа.
    2015-09-17 16: 13: 56Z

Ради полноты, начиная с .NET 4.0 , код можно переписать так:

 
Guid.TryParse(queryString["web"], out WebId);

TryParse никогда не генерирует исключения и возвращает false, если неверный формат, для WebId установлено значение Guid.Empty.

Начиная с C # 7 , вы можете не вводить переменную в отдельной строке:

 
Guid.TryParse(queryString["web"], out Guid webId);

Вы также можете создать методы для анализа возвращаемых кортежей, которые еще не доступны в .NET Framework начиная с версии 4.6:

 
(bool success, Guid result) TryParseGuid(string input) =>
    (Guid.TryParse(input, out Guid result), result);

И используйте их так:

 
WebId = TryParseGuid(queryString["web"]).result;
// or
var tuple = TryParseGuid(queryString["web"]);
WebId = tuple.success ? tuple.result : DefaultWebId;

Следующее бесполезное обновление этого бесполезного ответа происходит, когда деконструкция out-параметров реализована в C # 12.:)

    
129
2017-03-18 12: 40: 01Z
  1. Точно - кратко, и вы полностью обходите снижение производительности обработки исключений, плохую форму преднамеренного использования исключений для управления потоком программ и мягкую направленность Ваша логика конверсии распространилась повсюду, немного здесь и немного там.
    2013-04-17 03: 56: 53Z
  2. Я знаю, что вы имели в виду, но, конечно, Guid.TryParse никогда не возвращает Guid.Empty. Если строка имеет неправильный формат, она устанавливает выходной параметр result равным Guid.Empty, но возвращает false. Я упоминаю об этом, потому что я видел код, который делает вещи в стиле Guid.TryParse(s, out guid); if (guid == Guid.Empty) { /* handle invalid s */ }, что обычно неверно, если s может быть строковым представлением Guid.Empty.
    2013-05-18 11: 39: 00Z
  3. вау, вы ответили на вопрос, за исключением того, что это не соответствует духу вопроса. Большая проблема в другом: (
    2013-05-18 20: 01: 31Z
  4. Правильный шаблон для использования TryParse, конечно, больше похож на if( Guid.TryParse(s, out guid){ /* success! */ } else { /* handle invalid s */ }, который не оставляет двусмысленности, как сломанный пример, где входное значение может фактически быть строковым представлением Guid.
    2014-02-22 01: 55: 47Z
  5. Этот ответ действительно может быть правильным в отношении Guid.Parse, но он упустил весь смысл исходного вопроса. Который не имеет ничего общего с Guid.Parse, но был связан с перехватом Exception vs FormatException /OverflowException /etc.
    2015-09-14 12: 39: 11Z

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

 
catch (Exception ex) when (ex is FormatException || ex is OverflowException) {
    WebId = Guid.Empty;
}

Некоторые люди думают, что этот код такой же, как

 
catch (Exception ex) {                
    if (ex is FormatException || ex is OverflowException) {
        WebId = Guid.Empty;
    }
    throw;
}

Но это не так. На самом деле это единственная новая функция в C # 6, которую невозможно эмулировать в предыдущих версиях. Во-первых, повторный бросок означает больше накладных расходов, чем пропуск улова. Во-вторых, это не семантически эквивалентно. Новая функция сохраняет стек без изменений при отладке кода. Без этой функции аварийный дамп менее полезен или даже бесполезен.

См. обсуждение этого в CodePlex . И пример, показывающий разницу .

    
72
2015-04-01 16: 04: 37Z
  1. Бросок без исключения сохраняет стек, но "throw ex" перезапишет его.
    2017-04-12 13: 18: 59Z

Фильтры исключений теперь доступны в c # 6+. Вы можете сделать

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

В C # 7.0+ вы можете комбинировать это и с сопоставлением с шаблоном

 
try
{
   await Task.WaitAll(tasks);
}
catch (Exception ex) when( ex is AggregateException ae )
{
   //do something with members of ae, say ae.InnerExceptions
}
    
61
2019-05-11 07: 46: 49Z

Если вы не хотите использовать оператор if в пределах областей catch, в C# 6.0 вы можете использовать синтаксис Exception Filters , который уже был поддержан CLR в предварительных версиях но существовал только в VB.NET/MSIL:

 
try
{
    WebId = new Guid(queryString["web"]);
}
catch (Exception exception) when (exception is FormatException || ex is OverflowException)
{
    WebId = Guid.Empty;
}

Этот код перехватит Exception только тогда, когда это InvalidDataException или ArgumentNullException.

На самом деле, вы можете поместить любое условие в это предложение when:

 
static int a = 8;

...

catch (Exception exception) when (exception is InvalidDataException && a == 8)
{
    Console.WriteLine("Catch");
}

Обратите внимание, что в отличие от оператора if внутри области действия catch, Exception Filters не может выбросить Exceptions, и когда они это делают, или когда условие не true, вместо этого будет оцениваться следующее условие catch:

 
static int a = 7;

static int b = 0;

...

try
{
    throw new InvalidDataException();
}
catch (Exception exception) when (exception is InvalidDataException && a / b == 2)
{
    Console.WriteLine("Catch");
}
catch (Exception exception) when (exception is InvalidDataException || exception is ArgumentException)
{
    Console.WriteLine("General catch");
}
  

Вывод: общий улов.

При наличии более одного true Exception Filter - будет принят первый:

 
static int a = 8;

static int b = 4;

...

try
{
    throw new InvalidDataException();
}
catch (Exception exception) when (exception is InvalidDataException && a / b == 2)
{
    Console.WriteLine("Catch");
}
catch (Exception exception) when (exception is InvalidDataException || exception is ArgumentException)
{
    Console.WriteLine("General catch");
}
  

Вывод: поймать.

И, как вы можете видеть в MSIL, код не переводится в операторы if, а в Filters, и Exceptions нельзя выбрасывать из областей, отмеченных Filter 1 и Filter 2, но фильтр, выбрасывающий Exception, не будет работать, также последнее значение сравнения, помещенное в стек до того, как команда endfilter определит успех /неудачу фильтра (Catch 1 XOR Catch 2 будет выполняться соответственно):

 Фильтры исключений MSIL

Кроме того, в частности, Guid имеет Guid.TryParse метод.

    
31
2015-10-07 18: 37: 42Z
  1. + 1 для показа нескольких фильтров и предоставления объяснения того, что происходит при использовании нескольких фильтров.
    2018-10-09 13: 59: 44Z

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

Кроме того, кажется, что оператор is может немного ухудшить производительность.

CA1800: не приводите без необходимости говорит «рассмотреть возможность проверки результата оператора« as »вместо этого», но если вы сделаете это, вы будете писать больше кода, чем если бы вы ловили каждое исключение отдельно.

Во всяком случае, вот что я хотел бы сделать:

 
bool exThrown = false;

try
{
    // Something
}
catch (FormatException) {
    exThrown = true;
}
catch (OverflowException) {
    exThrown = true;
}

if (exThrown)
{
    // Something else
}
    
18
2015-04-09 14: 09: 55Z
  1. Но имейте в виду, что вы не можете перебросить исключение без потери трассировки стека, если вы сделаете это так. (См. Комментарий Майкла Стума к принятому ответу)
    2010-12-09 11: 27: 20Z
  2. Этот шаблон можно улучшить, сохранив исключение (пожалуйста, извините за плохое форматирование - я не могу понять, как поместить код в комментарии): Exception ex = null ; try {//что-то} catch (FormatException e) {ex = e; } catch (OverflowException e) {ex = e; } if (ex! = null) {//что-то еще и иметь дело с ex}
    2012-03-16 20: 03: 35Z
  3. @ JesseWeigert: 1. Вы можете использовать обратные пометки, чтобы придать фрагменту текста шрифт с одним интервалом и светло-серый фон. 2. Вы по-прежнему не сможете сбросить исходное исключение , включая трассировку стека .
    2012-11-22 17: 19: 07Z
  4. @ CleverNeologism, хотя может быть и так, что использование оператора is может оказать небольшое отрицательное влияние на производительность, также верно, что обработчик исключений не место для чрезмерно обеспокоен оптимизацией производительности. Если ваше приложение тратит так много времени на обработчики исключений, что оптимизация производительности может существенно повлиять на производительность приложения, то есть другие проблемы с кодом, на которые следует обратить пристальное внимание. Сказав это, мне все еще не нравится это решение, потому что вы теряете трассировку стека и потому что очистка контекстуально удаляется из оператора catch.
    2015-09-15 07: 22: 11Z
  5. Единственный раз, когда оператор is снижает производительность, это если вы позже выполняете операцию as (следовательно, они квалифицируют правило с без необходимости ). Если все, что вы делаете, - это тестирование приведения без необходимости его приведения, то оператор is - это именно то, что вы хотите использовать.
    2015-11-13 16: 25: 20Z

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

 
 try
 {
      throw new OverflowException();
 }
 catch(Exception e ) when ((e is DivideByZeroException) || (e is OverflowException))
 {
       // this will execute iff e is DividedByZeroEx or OverflowEx
       Console.WriteLine("E");
 }
    
18
2015-10-07 07: 53: 58Z

С помощью C # 7 ответ от Майкла Стума можно улучшить, сохранив читабельность оператора switch:

 
catch (Exception ex)
{
    switch (ex)
    {
        case FormatException _:
        case OverflowException _:
            WebId = Guid.Empty;
            break;
        default:
            throw;
    }
}
    
18
2018-01-05 11: 43: 42Z
  1. Это должен быть принятый ответ с IMHO 2018 года.
    2018-08-09 15: 38: 51Z
  2. Ответ Мэтта J, использующий when, гораздо более элегантен /уместен, чем переключатель.
    2018-11-06 15: 03: 21Z
  3. @ rgoliveira: Я согласен, что для случая, заданного в вопросе, ответ от Mat J более элегантный и подходящий. Тем не менее, становится трудно читать, если у вас есть другой код, который вы хотите выполнить в зависимости от типа исключения или если вы действительно хотите использовать экземпляр исключения. Все эти сценарии могут рассматриваться одинаково с этим оператором switch.
    2018-11-07 13: 47: 38Z
  4. @ Fabian "если у вас другой код, который вы хотите выполнить в зависимости от типа исключения, или если вы действительно хотите использовать экземпляр исключения", тогда вы просто делаете другой блок catch, или вам все равно придется его разыграть ... По моему опыту, throw; в вашем блоке catch, вероятно, является запахом кода.
    2018-11-07 16: 05: 41Z
  5. @ rgoliveira: использование метода throw в блоке catch в некоторых случаях приемлемо, см. ссылка . Поскольку в заявлении о деле фактически используется ссылка , то вы не используете нужно привести, если вы замените оператор сброса ссылкой (подчеркивание) по имени переменной. Не поймите меня неправильно, я согласен с вами, что фильтры исключений - более чистый способ сделать это, но несколько блоков catch добавляют много фигурных скобок.
    2018-11-08 17: 30: 43Z

Это вариант ответа Мэтта (мне кажется, он немного чище) ... используйте метод:

 
public void TryCatch(...)
{
    try
    {
       // something
       return;
    }
    catch (FormatException) {}
    catch (OverflowException) {}

    WebId = Guid.Empty;
}

Будут сгенерированы любые другие исключения, и код WebId = Guid.Empty; не будет принят. Если вы не хотите, чтобы другие исключения вызывали сбой вашей программы, просто добавьте это ПОСЛЕ двух других зацепок:

 
...
catch (Exception)
{
     // something, if anything
     return; // only need this if you follow the example I gave and put it all in a method
}
    
17
2013-10-11 20: 52: 50Z
  1. - 1 Это выполнит WebId = Guid.Emtpy в случае, когда не было выдано исключение.
    2012-10-23 13: 41: 38Z
  2. @ sepster Я думаю, что здесь подразумевается выражение возврата после "//что-то". Мне не очень нравится решение, но это конструктивный вариант в обсуждении. +1, чтобы отменить ваше пониженное голосование: -)
    2012-10-23 21: 12: 57Z
  3. @ Sepster toong прав, я предположил, что если вы хотите вернуть туда, то вы бы поставили один ... Я пытался сделать мой ответ достаточно общим, чтобы применить ко всем ситуациям, если другие с похожими, но не точными вопросами также выиграют. Однако, для хорошей меры, я добавил return к своему ответу. Спасибо за вклад.
    2012-10-24 17: 27: 37Z

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

 
catch(Exception ex)
{   
    if (!(ex is SomeException || ex is OtherException)) throw;

    // Handle exception
}

Есть несколько преимуществ обращения выражения:

  • оператор возврата не требуется
  • Код не является вложенным
  • Там внет риска забыть утверждения «throw» или «return», которые в решении Иосифа отделены от выражения.

Он даже может быть сжат до одной строки (хотя и не очень красиво)

 
catch(Exception ex) { if (!(ex is SomeException || ex is OtherException)) throw;

    // Handle exception
}

Edit: фильтрация исключений в C # 6.0 сделает синтаксис немного чище и будет иметь ряд других преимуществ по сравнению с любым текущим решением. (прежде всего оставляя стек без повреждений)

Вот как будет выглядеть та же проблема с использованием синтаксиса C # 6.0:

 
catch(Exception ex) when (ex is SomeException || ex is OtherException)
{
    // Handle exception
}
    
17
2017-05-23 10: 31: 35Z
  1. + 1, это лучший ответ. Это лучше, чем верхний ответ, в основном потому, что нет return, хотя инвертирование условия также немного лучше.
    2015-03-18 20: 22: 32Z
  2. Я даже не думал об этом. Хороший улов, я добавлю его в список.
    2015-03-20 00: 35: 32Z

@Micheal р>

Немного переработанная версия вашего кода:

 
catch (Exception ex)
{
   Type exType = ex.GetType();
   if (exType == typeof(System.FormatException) || 
       exType == typeof(System.OverflowException)
   {
       WebId = Guid.Empty;
   } else {
      throw;
   }
}

Строковые сравнения уродливы и медленны.

    
16
2008-09-25 21: 16: 23Z
  1. Почему бы просто не использовать ключевое слово "is"?
    2008-09-25 21: 02: 47Z
  2. @ Michael - Если Microsoft представила, скажем, StringTooLongException, полученную из FormatException, то это все еще исключение формата, просто конкретное. Это зависит от того, хотите ли вы семантику «поймать этот точный тип исключения» или «поймать исключения, которые означают, что формат строки был неправильным».
    2008-09-25 21: 19: 31Z
  3. @ Michael - Также обратите внимание, что у "catch (FormatException ex) есть последняя семантика, она будет перехватывать все, что происходит от FormatException.
    2008-09-25 21: 21: 23Z
  4. @ Alex No. "throw" без "ex" переносит исходное исключение, включая исходную трассировку стека, вверх. Добавление «ex» приводит к сбросу трассировки стека, так что вы получите исключение, отличное от оригинала. Я уверен, что кто-то другой может объяснить это лучше, чем я. :)
    2010-09-22 22: 04: 22Z
  5. - 1: Этот код чрезвычайно хрупок - разработчик библиотеки может рассчитывать заменить throw new FormatException(); на throw new NewlyDerivedFromFormatException();, не нарушая код с помощью библиотеки, и он будет сохраняться для всей обработки исключений кроме случаев, когда кто-то использовал == вместо is (или просто catch (FormatException)).
    2013-07-17 03: 47: 34Z

Как насчет

 
try
{
    WebId = Guid.Empty;
    WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
}
catch (OverflowException)
{
}
    
13
2013-03-22 15: 58: 32Z
  1. Это работает, только если Catch-код может быть полностью перемещен в Try-Block. Но код обработки изображений, в котором вы выполняете несколько манипуляций с объектом, а одна посередине, терпит неудачу, и вы хотите «сбросить» объект.
    2008-09-25 20: 59: 36Z
  2. В этом случае я бы добавил функцию сброса и вызвал бы ее из нескольких блоков catch.
    2008-09-25 21: 04: 02Z

Предупреждение и предупреждение. Еще один вид , функциональный стиль.

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

 
static void Main() 
{ 
    Action body = () => { ...your code... };

    body.Catch<InvalidOperationException>() 
        .Catch<BadCodeException>() 
        .Catch<AnotherException>(ex => { ...handler... })(); 
}

(по сути, предоставляет еще одну пустую перегрузку Catch, которая возвращает себя)

Главный вопрос - почему . Я не думаю, что стоимость перевешивает выигрыш здесь:)

    
11
2013-05-18 11: 28: 30Z
  1. Одним из возможных преимуществ этого подхода является то, что существует семантическая разница между перехватом и повторным выбросом исключения по сравнению с его отсутствием; в некоторых случаях код должен действовать на исключение без его перехвата. Такое возможно в vb.net, но не в C # , если не используется оболочка, написанная на vb.net и вызываемая из C #.
    2013-07-17 02: 43: 23Z
  2. Как действует исключение, не перехватывая его? Я не до конца понимаю вас.
    2013-07-17 07: 20: 45Z
  3. @ nawful ... с использованием фильтра vb - функция filter (ex в качестве исключения): LogEx (ex): вернуть false ... затем в строке catch: catch ex когда фильт (бывший)
    2015-10-07 18: 15: 59Z
  4. @ FastAl Разве это не разрешено фильтрами исключений в C # 6?
    2016-09-22 11: 52: 54Z
  5. @ HimBromBeere да, это прямые аналоги
    2016-09-22 14: 31: 44Z
 
catch (Exception ex)
{
    if (!(
        ex is FormatException ||
        ex is OverflowException))
    {
        throw;
    }
    Console.WriteLine("Hello");
}
    
11
2014-10-30 11: 15: 16Z

Обновление 2015-12-15: см. https://stackoverflow.com/a/22864936/1718702 для C # 6. Это чище и теперь стандарт в языке.

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

У меня уже было это расширение в моей библиотеке, изначально написанное для других целей, но оно отлично работало для type проверки исключений. Плюс, имхо, это выглядит чище, чем куча || заявлений. Кроме того, в отличие от принятого ответа, я предпочитаю явную обработку исключений, чтобы ex is ... имел нежелательное поведение, так как производные классы можно назначать родительским типам).

Использование

 
if (ex.GetType().IsAnyOf(
    typeof(FormatException),
    typeof(ArgumentException)))
{
    // Handle
}
else
    throw;

Расширение IsAnyOf.cs (см. пример полной обработки ошибок для зависимостей)

 
namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter matches at least one of the passed in comparisons.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_comparisons">Values to compare against.</param>
        /// <returns>True if a match is found.</returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static bool IsAnyOf<T>(this T p_parameter, params T[] p_comparisons)
        {
            // Validate
            p_parameter
                .CannotBeNull("p_parameter");
            p_comparisons
                .CannotBeNullOrEmpty("p_comparisons");

            // Test for any match
            foreach (var item in p_comparisons)
                if (p_parameter.Equals(item))
                    return true;

            // Return no matches found
            return false;
        }
    }
}

Пример полной обработки ошибок (копирование-вставка в новое консольное приложение)

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.FluentValidation;

namespace IsAnyOfExceptionHandlerSample
{
    class Program
    {
        static void Main(string[] args)
        {
            // High Level Error Handler (Log and Crash App)
            try
            {
                Foo();
            }
            catch (OutOfMemoryException ex)
            {
                Console.WriteLine("FATAL ERROR! System Crashing. " + ex.Message);
                Console.ReadKey();
            }
        }

        static void Foo()
        {
            // Init
            List<Action<string>> TestActions = new List<Action<string>>()
            {
                (key) => { throw new FormatException(); },
                (key) => { throw new ArgumentException(); },
                (key) => { throw new KeyNotFoundException();},
                (key) => { throw new OutOfMemoryException(); },
            };

            // Run
            foreach (var FooAction in TestActions)
            {
                // Mid-Level Error Handler (Appends Data for Log)
                try
                {
                    // Init
                    var SomeKeyPassedToFoo = "FooParam";

                    // Low-Level Handler (Handle/Log and Keep going)
                    try
                    {
                        FooAction(SomeKeyPassedToFoo);
                    }
                    catch (Exception ex)
                    {
                        if (ex.GetType().IsAnyOf(
                            typeof(FormatException),
                            typeof(ArgumentException)))
                        {
                            // Handle
                            Console.WriteLine("ex was {0}", ex.GetType().Name);
                            Console.ReadKey();
                        }
                        else
                        {
                            // Add some Debug info
                            ex.Data.Add("SomeKeyPassedToFoo", SomeKeyPassedToFoo.ToString());
                            throw;
                        }
                    }
                }
                catch (KeyNotFoundException ex)
                {
                    // Handle differently
                    Console.WriteLine(ex.Message);

                    int Count = 0;
                    if (!Validate.IsAnyNull(ex, ex.Data, ex.Data.Keys))
                        foreach (var Key in ex.Data.Keys)
                            Console.WriteLine(
                                "[{0}][\"{1}\" = {2}]",
                                Count, Key, ex.Data[Key]);

                    Console.ReadKey();
                }
            }
        }
    }
}

namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter matches at least one of the passed in comparisons.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_comparisons">Values to compare against.</param>
        /// <returns>True if a match is found.</returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static bool IsAnyOf<T>(this T p_parameter, params T[] p_comparisons)
        {
            // Validate
            p_parameter
                .CannotBeNull("p_parameter");
            p_comparisons
                .CannotBeNullOrEmpty("p_comparisons");

            // Test for any match
            foreach (var item in p_comparisons)
                if (p_parameter.Equals(item))
                    return true;

            // Return no matches found
            return false;
        }

        /// <summary>
        /// Validates if any passed in parameter is equal to null.
        /// </summary>
        /// <param name="p_parameters">Parameters to test for Null.</param>
        /// <returns>True if one or more parameters are null.</returns>
        public static bool IsAnyNull(params object[] p_parameters)
        {
            p_parameters
                .CannotBeNullOrEmpty("p_parameters");

            foreach (var item in p_parameters)
                if (item == null)
                    return true;

            return false;
        }
    }
}

namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter is not null, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void CannotBeNull(this object p_parameter, string p_name)
        {
            if (p_parameter == null)
                throw
                    new
                        ArgumentNullException(
                        string.Format("Parameter \"{0}\" cannot be null.",
                        p_name), default(Exception));
        }
    }
}

namespace Common.FluentValidation
{
    public static partial class Validate
    {
        /// <summary>
        /// Validates the passed in parameter is not null or an empty collection, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static void CannotBeNullOrEmpty<T>(this ICollection<T> p_parameter, string p_name)
        {
            if (p_parameter == null)
                throw new ArgumentNullException("Collection cannot be null.\r\nParameter_Name: " + p_name, default(Exception));

            if (p_parameter.Count <= 0)
                throw new ArgumentOutOfRangeException("Collection cannot be empty.\r\nParameter_Name: " + p_name, default(Exception));
        }

        /// <summary>
        /// Validates the passed in parameter is not null or empty, throwing a detailed exception message if the test fails.
        /// </summary>
        /// <param name="p_parameter">Parameter to validate.</param>
        /// <param name="p_name">Name of tested parameter to assist with debugging.</param>
        /// <exception cref="ArgumentException"></exception>
        public static void CannotBeNullOrEmpty(this string p_parameter, string p_name)
        {
            if (string.IsNullOrEmpty(p_parameter))
                throw new ArgumentException("String cannot be null or empty.\r\nParameter_Name: " + p_name, default(Exception));
        }
    }
}

Два примера модульных тестов NUnit

Соответствие поведения для Exception типов является точным (т. е. дочерний элемент НЕ соответствует ни одному из своих родительских типов).

 
using System;
using System.Collections.Generic;
using Common.FluentValidation;
using NUnit.Framework;

namespace UnitTests.Common.Fluent_Validations
{
    [TestFixture]
    public class IsAnyOf_Tests
    {
        [Test, ExpectedException(typeof(ArgumentNullException))]
        public void IsAnyOf_ArgumentNullException_ShouldNotMatch_ArgumentException_Test()
        {
            Action TestMethod = () => { throw new ArgumentNullException(); };

            try
            {
                TestMethod();
            }
            catch (Exception ex)
            {
                if (ex.GetType().IsAnyOf(
                    typeof(ArgumentException), /*Note: ArgumentNullException derrived from ArgumentException*/
                    typeof(FormatException),
                    typeof(KeyNotFoundException)))
                {
                    // Handle expected Exceptions
                    return;
                }

                //else throw original
                throw;
            }
        }

        [Test, ExpectedException(typeof(OutOfMemoryException))]
        public void IsAnyOf_OutOfMemoryException_ShouldMatch_OutOfMemoryException_Test()
        {
            Action TestMethod = () => { throw new OutOfMemoryException(); };

            try
            {
                TestMethod();
            }
            catch (Exception ex)
            {
                if (ex.GetType().IsAnyOf(
                    typeof(OutOfMemoryException),
                    typeof(StackOverflowException)))
                    throw;

                /*else... Handle other exception types, typically by logging to file*/
            }
        }
    }
}
    
9
2017-05-23 10: 31: 35Z
  1. Расширение языка не «более изящно». Во многих местах это фактически создало адский уровень обслуживания. Спустя годы многие программисты не гордятся тем, какого монстра они создали. Это не то, что вы привыкли читать. Это может вызвать "да?" эффект или даже серьезные "WTFs". Это иногда сбивает с толку. Единственное, что он делает - это усложняет понимание кода для тех, кому нужно иметь дело с ним позже в процессе обслуживания - только потому, что один программист пытался быть «умным». За эти годы я узнал, что эти «умные» решения редко бывают полезнымииз них.
    2014-10-09 21: 02: 42Z
  2. или в двух словах: придерживайтесь возможностей, которые предоставляет родной язык. не пытайтесь переопределить семантику языка только потому, что вам они не нравятся. Честно говоря, ваши коллеги (и, возможно, я будущие) будут вам благодарны.
    2014-10-09 21: 07: 15Z
  3. Также обратите внимание, что ваше решение только приближает семантику C # 6 when, как и любая версия catch (Exception ex) {if (...) {/*handle*/} throw;}. Реальное значение when состоит в том, что фильтр запускается до того, как исключение будет перехвачено , что позволяет избежать повреждения затрат /стека при повторном выбросе. Он использует функцию CLR, которая ранее была доступна только для VB и MSIL.
    2016-06-27 14: 55: 35Z
  4. Более элегантно? Этот пример настолько велик для такой простой задачи, а код выглядит так ужасно, что даже не стоило на него смотреть. Пожалуйста, не делайте этот код чужой проблемой в реальном проекте.
    2016-12-28 16: 02: 47Z
  5. весь ваш метод IsAnyOf можно переписать просто как p_comparisons.Contains(p_parameter)
    2017-07-27 16: 04: 25Z

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

То, что мы действительно хотим сделать, это то, что не компилируется, скажем:

 
// Won't compile... damn
public static void Main()
{
    try
    {
        throw new ArgumentOutOfRangeException();
    }
    catch (ArgumentOutOfRangeException)
    catch (IndexOutOfRangeException) 
    {
        // ... handle
    }

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

Так почему этот код не скомпилируется - и как мы можем взломать его таким образом, чтобы он был?

Если мы посмотрим на код, то на самом деле нам хотелось бы переадресовать вызов. Однако, согласно MS Partition II, блоки обработчиков исключений IL не будут работать таким образом, что в этом случае имеет смысл, поскольку это подразумевает, что объект «исключения» может иметь разные типы.

Или, чтобы написать это в коде, мы просим компилятор сделать что-то подобное (ну, это не совсем правильно, но я думаю, это самая близкая вещь):

 
// Won't compile... damn
try
{
    throw new ArgumentOutOfRangeException();
}
catch (ArgumentOutOfRangeException e) {
    goto theOtherHandler;
}
catch (IndexOutOfRangeException e) {
theOtherHandler:
    Console.WriteLine("Handle!");
}

Причина, по которой это не скомпилируется, совершенно очевидна: какой тип и значение будет иметь объект $exception (которые здесь хранятся в переменных 'e')? Мы хотим, чтобы компилятор справился с этим, отметив, что общим базовым типом обоих исключений является «Исключение», используйте его для переменной, содержащей оба исключения, а затем обрабатывайте только два захваченных исключения. Способ, которым это реализовано в IL, является «фильтром», который доступен в VB.Net.

Чтобы он работал в C #, нам нужна временная переменная с правильным базовым типом «Exception». Чтобы контролировать поток кода, мы можем добавить несколько веток. Здесь идет:

 
    Exception ex;
    try
    {
        throw new ArgumentException(); // for demo purposes; won't be caught.
        goto noCatch;
    }
    catch (ArgumentOutOfRangeException e) {
        ex = e;
    }
    catch (IndexOutOfRangeException e) {
        ex = e;
    }

    Console.WriteLine("Handle the exception 'ex' here :-)");
    // throw ex ?

noCatch:
    Console.WriteLine("We're done with the exception handling.");

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

 
Exception ex = null;
try
{
    throw new ArgumentException();
}
catch (ArgumentOutOfRangeException e)
{
    ex = e;
}
catch (IndexOutOfRangeException e)
{
    ex = e;
}
if (ex != null)
{
    Console.WriteLine("Handle the exception here :-)");
}

Это оставляет только «перебросить». Чтобы это работало, нам нужно иметь возможность выполнять обработку внутри блока «catch» - и единственный способ выполнить эту работу - перехватывать объект «Exception».

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

 
private static bool Handle(Exception e)
{
    Console.WriteLine("Handle the exception here :-)");
    return true; // false will re-throw;
}

public static void Main()
{
    try
    {
        throw new OutOfMemoryException();
    }
    catch (ArgumentException e)
    {
        if (!Handle(e)) { throw; }
    }
    catch (IndexOutOfRangeException e)
    {
        if (!Handle(e)) { throw; }
    }

    Console.WriteLine("We're done with the exception handling.");

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

 
try
{
    throw new ArgumentException();
}
catch (Exception e)
{
    Exception ex = (Exception)(e as ArgumentException) ?? (e as IndexOutOfRangeException);
    if (ex != null)
    {
        Console.WriteLine("Handle the exception here :-)");
        // throw ?
    }
    else 
    {
        throw;
    }
}

Итак, сделайте вывод:

  • Если мы не хотим перебрасывать, мы можем рассмотреть возможность перехвата правильных исключений и их временного хранения.
  • Если обработчик прост, и мы хотим повторно использовать код, лучшим решением, вероятно, является введение вспомогательной функции.
  • Если мы хотим перебросить, у нас нет другого выбора, кроме как поместить код в обработчик перехвата 'Exception', который сломает FxCop и неперехваченные исключения вашего отладчика.
7
2014-10-21 09: 44: 02Z

Это классическая проблема, с которой сталкивается каждый разработчик C #.

Позвольте мне разбить ваш вопрос на 2 вопроса. Первый,

Могу ли я поймать несколько исключений одновременно?

Короче говоря, нет.

Что приводит к следующему вопросу,

Как избежать написания дублирующего кода, если я не могу перехватить несколько типов исключений в одном блоке catch ()?

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

  1. Инициализируйте WebId в качестве запасного значения.
  2. Создайте новый Guid во временной переменной.
  3. Установите для WebId полностью созданную временную переменную. Сделайте это последним утверждением блока try {}.

Итак, код выглядит так:

 
try
{
    WebId = Guid.Empty;
    Guid newGuid = new Guid(queryString["web"]);
    // More initialization code goes here like 
    // newGuid.x = y;
    WebId = newGuid;
}
catch (FormatException) {}
catch (OverflowException) {}

Если выдается какое-либо исключение, то для WebId никогда не устанавливается половинное значение и он остается Guid.Empty.

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

 
try
{
    WebId = new Guid(queryString["web"]);
    // More initialization code goes here.
}
catch (FormatException) {
    Reset(WebId);
}
catch (OverflowException) {
    Reset(WebId);
}
    
7
2017-11-15 20: 27: 32Z
  1. Это хорошая "экологическая кодировка", т.е. вы думаете о своем коде & следы данных и убедитесь, что нет утечки половины обработанных значений. Приятно будет следовать этому шаблону, спасибо Джеффри!
    2018-03-05 00: 44: 07Z

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

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

 
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); 
}
    
6
2017-05-23 11: 47: 26Z
  1. "Интересно, почему никто не заметил это дублирование кода." - ну что? Суть вопроса заключается в устранении дублирования кода.
    2017-10-23 22: 03: 24Z

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

Например, если вы используете исключение «catch-all» в качестве Exception , оно будет предшествовать всем остальным операторам catch, и вы, очевидно, получите ошибки компилятора, однако, если вы измените порядок в обратном порядке, вы можете объединить ваш улов с утверждениями (немного анти-паттерна, я думаю), вы можете поместить тип catch-all Exception внизу, и это будет захватывать любые исключения, которые не учитывались при повышении в вашей попытке .. блок 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
2017-04-16 15: 51: 04Z

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

например:.

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

// ...

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

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

    
4
2018-01-23 14: 02: 59Z

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

 
catch (Exception ex)
{
    switch (ex.GetType().Name)
    {
        case "System.FormatException":
        case "System.OverflowException":
            WebId = Guid.Empty;
            break;
        default:
            throw;
    }
}
    
1
2015-04-09 14: 07: 34Z
  1. - 1 голос, +5 WTF :-) Этот ответ не должен быть помечен как ответ, но он бесполезен.
    2008-09-25 21: 23: 19Z
  2. Не имеет значения, насколько просто мы могли бы это сделать. Но он не сидел без дела и высказал свое мнение, чтобы решить это. Очень ценю.
    2016-01-21 10: 27: 36Z
  3. Хотя на самом деле не делайте этого, используйте фильтры исключений в C # 6 или любой другой ответ - я специально обозначил это как «Это один из способов, но это плохо и я хочу сделать что-то лучше ".
    2016-01-21 19: 16: 45Z
  4. ПОЧЕМУ это плохо? Я был озадачен тем, что вы не можете напрямую использовать исключение в операторе switch.
    2016-06-08 14: 02: 18Z
  5. @ MKesper Я вижу несколько причин, по которым это плохо. Это требует написания полных имен классов в виде строковых литералов, что уязвимо для опечаток, от которых компилятор не сможет вас спасти. (Это важно, поскольку во многих магазинах случаи ошибок менее проверены, и поэтому тривиальные ошибки в них, скорее всего, будут упущены.) Также не удастся найти исключение, которое является подклассом одного из указанных случаев. Кроме того, из-за того, что они являются строками, случаи будут пропущены такими инструментами, как VS «Найти все ссылки» - это уместно, если вы хотите добавить шаг очистки везде, где обнаруживается определенное исключение.
    2017-10-23 22: 18: 03Z

Здесь стоит упомянуть. Вы можете ответить на несколько комбинаций (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
2018-12-07 15: 14: 45Z

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

 
        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
2019-05-27 14: 18: 24Z

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

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

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

    
- 14
2016-07-29 04: 42: 02Z
  1. ит. это побеждает цель вопроса. Он задает этот вопрос, чтобы избавиться от дубликата кода. гоЭто ответ добавляет больше повторяющегося кода.
    2017-02-23 21: 40: 12Z

В 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");
    }
}
    
- 22
2015-05-20 07: 48: 59Z
  1. В этом примере не показано использование фильтров исключений.
    2015-05-27 13: 37: 27Z
  2. Это стандартный способ фильтрации исключений в c # 6.0
    2015-05-27 13: 42: 49Z
  3. Посмотрите еще раз, что такое фильтры исключений. Вы не используете фильтр исключений в своем примере. В этом ответе , опубликованном за год до того, есть подходящий пример.
    2015-05-27 13: 44: 10Z
  4. Примером фильтрации исключений будет catch (HttpException e) when e.GetHttpCode() == 400 { WriteLine("Bad Request"; }
    2015-11-13 16: 29: 11Z
  5. Это не показывает способ фильтрации исключений: /
    2016-03-01 02: 51: 49Z
источник размещен Вот