Как провести рефакторинг для уменьшения глубины вложенности с помощью try/multiple catch (NDepend)

В следующем коде NDepend сообщает о нарушении из-за глубины вложенности 6 (1 для каждого улова) и предела 5. Таким образом, он помечен в это правило:

Краткий обзор методов рефакторинга

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

private static void _TryDeleteFile(string filename)
{
    try
    {
        File.Delete(filename);
    }
    catch (ArgumentException innerEx)
    {
         // do something
    }
    catch (DirectoryNotFoundException innerEx)
    {
        // do something
    }
    catch (PathTooLongException innerEx)
    {
        // do something
    }
    catch (IOException innerEx)
    {
        // do something
    }
    catch (NotSupportedException innerEx)
    {
        // do something
    }
    catch (UnauthorizedAccessException innerEx)
    {
        // do something
    }
}

person Jerry R    schedule 12.11.2014    source источник
comment
Я предлагаю вам повторное голосование, потому что похоже, что вы прилагаете усилия для улучшения своего вопроса, каждый раз, когда вы упоминаете какую-либо ошибку или исключение, включайте полный текст сообщения, дословно (используйте > в начале, чтобы процитировать его ). Кроме того, всегда включайте тег для языка программирования, иначе сообщение не увидит большинство экспертов в данной области.   -  person Adi Inbar    schedule 12.11.2014
comment
Спасибо, предложение теперь интегрировано.   -  person Jerry R    schedule 12.11.2014
comment
Теперь у вас есть 4 повторных голосования, нужно еще одно.   -  person Adi Inbar    schedule 12.11.2014


Ответы (1)


Во-первых, блоки try/catch не так элегантны для работы в C#, как могли бы быть, и это просто то, с чем нам пока приходится смириться.

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

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

Рефакторинг может заключаться в том, чтобы сохранить набор «обработчиков исключений» (либо классов, либо действий) в словаре, фабричном классе или ядре IOC. Затем вы можете указать обработчик исключений в одной строке кода. Это уменьшит вложенность, но внесет свою сложность. Что-то вроде этого:

try
{
   /* Your code */
}
catch(Exception ex)
{
    var exceptionHandler = _exceptionHandlers[ex.GetType()];
    exceptionHandler.Execute(ex);
}

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

person cbp    schedule 12.11.2014
comment
или, возможно: if (!_exceptionHandlers.TryGetValue(ex.GetType, out exceptionHandler)) throw ex; исключениеHandler.Execute(ex) - person Jerry R; 13.11.2014