Поймать исключение с условием - PullRequest
8 голосов
/ 29 сентября 2010

Примечание: я очень рад сообщить вам, что фильтры исключений теперь на языке C # 6.0.

Это мысленный эксперимент, меня интересует ваше мнение:это имеет смысл для вас?Знаете ли вы, что подобное было уже предложено для языка программирования C #?Я бы даже не знал, куда отправить такое предложение ...

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

Один пример использования - при работе с COM Interop: все всегда выдает COMException.Фактический отличительный код ошибки содержится в его сообщении.

Так что насчет (предложение 1):

try
{
    ...
}
catch (COMException ex where ex.Message.Contains("0x800706BA"))
{
    // RPC server unavailable
}
catch (COMException ex where ex.Message.Contains("0x80010001"))
{
    // Call rejected by callee
}

, что означает:

try
{
    ...
}
catch (COMException ex)
{
    if (ex.Message.Contains("0x800706BA"))
    {
        // RPC server unavailable
    }
    else if (ex.Message.Contains("0x80010001"))
    {
        // Call rejected by callee
    }
    else
    {
        throw;
    }
}

Подобные случаи: SoapException, XmlException ...


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

Скажем, у нас есть API, который охватывает исключения вроде этого: catch (NumberFormatException ex) { throw new BusinessException(ex) }.

Как насчет (предложение 2А):

try
{
    ...
}
catch (inner NumberFormatException nfex)
{
    ...
}

, что означает:

catch (Exception ex where ex.InnerException is NumberFormatException)
{
    NumberFormatException nfex = ex.InnerException;
    ...
}

или (2B):

catch (BusinessException bex inner NumberFormatException nfex)
{
    ...
}

, что означает:

catch (BusinessException bex where bex.InnerException is NumberFormatException)
{
    NumberFormatException nfex = bex.InnerException;
    ...
}

В в этом случае(родом из Java) может выглядеть (2C):

catch (RemoteAccessException raex inner inner MyException mex)
{
    ...
}

Ответы [ 7 ]

21 голосов
/ 17 июня 2015

В соответствии с try-catch C # Reference для Visual Studio 2015 RC это теперь реализовано:

Catch (ArgumentException e) when (e.ParamName == "…")
{
}
8 голосов
/ 29 сентября 2010

VB.Net имеет эту функцию фильтра исключений, как показано ниже

Catch ex As COMException When ex.ErrorCode = 0x800706BA

Так что это поддерживается CLR, но функция не предоставляется в C #

Предположительно, F # имеет эту функциютакже, но я не знаю много о F #, чтобы показать пример.

4 голосов
/ 29 сентября 2010

Исключения и типы тесно связаны.Если вы хотите различать два разных типа исключений, вы должны сделать два типа исключений.В вашем примере вы бы имели исключение Com800706BAException и Com80010001Exception.

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

catch (Exception e where e.Message = "The foo barfed up the bar")

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

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

2 голосов
/ 29 сентября 2010

Я думаю, это довольно сложно и запутанно:

Что если ваше условие исключения также вызывает исключение? Где и как должно обрабатываться это новое исключение?

  • Пробовать / ловить вокруг блока ловли? Мех ..
  • Пусть другие блоки перехвата обрабатывают это исключение: StackOverflows yay:)
2 голосов
/ 29 сентября 2010

Зачем печь что-то на языке, который в любом случае тривиально сделать?

Предложение 1 легко решается с помощью целевого оператора switch внутри catch - таким образом вы можете работать с COM-исключениями, которые хотите, и просто отбрасывать все, с чем не хотите иметь дело.

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

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

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

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

*, игнорируя тот факт, что все исключения происходят из System.Exception - я имел в виду больше в соответствии с MyBaseException , из которого происходят все ваши пользовательские исключения.

1 голос
/ 05 ноября 2017

Начиная с c # 7.0 такого рода вещи уже поддерживаются. Здесь - полный справочник. Вот фрагмент кода.

    try
    {
        SomeOperationThatThrowsException();
    }
    catch(TheFilteredException ex ) when (ex.ErrorCode==123)
    {
        DoSomethingWhenExceptionThrown();
    }
1 голос
/ 29 сентября 2010

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

Какмало кто уже указывал, это уже в VB, однако вы легко могли бы сделать что-то подобное в C #:

catch (Exception ex)
{
  if (ex.Message.Contains("Yikes!"))
  {
    // Do your thing
  }
  ...
  else
  {
    throw;
  }
}

Так что это действительно просто синтаксический сахар.

Что касается исключенийв том, что (как часто обсуждается на этом сайте) они нарушают последовательную структуру вашей программы, потенциально пропуская много кода и выталкивая стек, когда вы действительно этого не хотели.Вот почему я не думаю, что они хороши ни для чего, кроме очень исключительных условий, и если вы действительно можете как-то справиться с этими условиями, это должно быть чем-то вроде боли (попробуйте {} catch {if (..)} и т. д.), чтобы люди не могли использовать исключения более чем для этих исключительных условий.

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