Умышленное повышение исключений для использования улова

10

if...elseЯвляется ли типичное завершение с обработкой исключений чем-то вроде следующего примера рекомендуемой практикой во избежание дублирования кода?

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

вместо...

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        return null;
    }
}
catch(Exception ex)
{
    return null;
}

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

grovesNL
источник
если метод достаточно мал, я просто удалю else и верну null за пределами блока trycatch, поэтому мне придется возвращать null только один раз.
Фабио Марколини

Ответы:

12

Microsoft не рекомендует использовать обработку исключений для управления потоком.

И круглый стол по теме доступен.

При этом C # поддерживает это, и я полагаю, что это зависит от того, с каким условием столкнулся, является ли исключение наиболее подходящим ответом.

B2K
источник
1
Меня поражает, что такого рода вещи просто очень стараются не использовать события.
Радар Боб
@radarbob: Как события связаны с этим?
@grovesNL - Выдает исключение в определенной точке для вызова определенного метода в блоке перехвата? Крякает как событие для меня.
Радар Боб
@radarbob: это не событие. Есть много примеров использования, где это будет использоваться, как обсуждено в ответе круглого стола ответа.
1
@radarbob Небольшое пояснение, исключения были разработаны как способ сообщить вызывающей стороне, что произошло что-то, что вызываемый метод не может обработать. Тем не менее, событие должно быть прослушано. Исключением является принудительное прерывание нормального потока программы. Неперехваченное исключение приведет к прекращению работы всего приложения.
6

Повышение производительности, скорее всего, незначительно, как объясняется в этом ответе .

Итак, давайте предположим, что производительность не является проблемой. Вы бросаете System.Exception, просто чтобы переместить исполнение в catchпункт . Бросать BadControlFlowThatShouldBeRewrittenException, вероятно, было бы излишним.

Давайте разберемся с этим. У нас есть:

  • Метод GetDataFromServer(имена методов должны быть PascalCase в C #), который может вызвать исключение или вернуть a bool.
  • Если результат был true, беги ProcessData.
  • Верните в nullпротивном случае.

Похоже, метод, в котором написан этот код, просто делает слишком много вещей. GetDataFromServerвозвращая boolвнешний вид как недостаток дизайна, я ожидал бы, что этот метод вернет данные, которые он получает с сервера , некоторые из IEnumerable<SomeType>которых будут содержать 0 или более элементов - т.е. счастливый путь возвращает n элементов, где n> 0 , не такой счастливый path возвращает 0 элементов, а несчастный путь разрывается с необработанным исключением, что бы это ни было.

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

try
{
    var result = GetDataFromServer();
    return ProcessData(result);
}
catch
{
    return null;
}

Здесь вы посмотрите ProcessDataи увидите, что он выполняет итерацию result, и возвращает, nullесли в IEnumerable.

Теперь, почему метод возвращается null? Сервер не работает? Есть ли ошибка в запросе? Строка подключения использует неправильные учетные данные? Всякий раз, когда GetDataFromServerвзрывается с исключением, которого вы не ожидаете, вы глотаете его, суете его под ковер и возвращаете nullзначение. Я бы порекомендовал отлавливать конкретные исключения в этом случае и регистрировать все остальное; отладка будет намного проще.

С общим catchпредложением, которое не фиксирует исключение, довольно сложно что-либо диагностировать. Я бы минимально сделал это вместо этого:

catch(Exception e)
{
    return null;
}

Теперь вы можете по крайней мере сломать и проверить, eесли что-то пойдет не так.


TL; DR : Нет, выбрасывать и перехватывать исключения для управления потоком данных не очень хорошая идея.

Матье Гиндон
источник
Этот ответ наглядно демонстрирует, почему я пытался сделать свой код универсальным: я не хотел перечислять каждое исключение, которое я фактически сделал в своем коде; Я не хотел перечислять реальные имена методов; Я не хотел перечислять объявление метода; Я не хотел предложений синтаксиса. У меня был один вопрос о том, нормально ли выбрасывать исключения для управления потоком, на что быстро ответил B2K. Я был бы рад обсудить это на мета.
3
Похоже, это должно было быть вопросом для программистов. мы пересматриваем код, а не идеи.
Малахи,
2

в вашем первом ответе есть падение производительности, которое не должно быть там.

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

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

если вы хотите return null; сделать это в операторе else, а не в подвохе, который перехватывается после выброса из оператора else.

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

Стандарты говорят, что вы не должны этого делать.

Стандарты говорят, что вы должны делать это так (опять же на основе общего кода, указанного в OP)

if (GetDataFromServer())
{
    return ProcessData();
}
else
{
    Return null
}

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

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

Малахия
источник
1

Почему не намного проще:

if (!GetDataFromServer()) return null;
ProcessData();

Если обработчик исключений будет существовать, он должен быть в ProcessData ()

Лорен Печтель
источник
Почему я не хочу передавать исключения ProcessData()на самый верхний уровень?
grovesNL
@grovesNL Ничего полезного не было сделано за исключением здесь.
Лорен Печтел
1
Как же так? Если ProcessData()выбрасывает исключение, оно не обрабатывается. Я хочу это return nullна этом уровне, если ProcessData()выдает исключение, не изменяя ProcessData()себя.
grovesNL