Форматирование трудночитаемых блоков try..catch..finally?

StackOverflow https://stackoverflow.com/questions/937426

Вопрос

Как вы форматируете блоки try..catch.finally?Особенно, если обернуть его лишь небольшим объемом кода, это все портит и делает код, на мой взгляд, довольно нечитабельным и неприглядным.

Такой как:

try
{
     MyService service = new Service();
     service.DoSomething();
     return something;
}
catch (Exception ex)
{
     LogSomething();
     return somethingElse;
}
finally
{
     MarkAsComplete();
     service.Dispose();
}

Эти 7 строк кода превратились в 16-строчную мешанину.

Есть какие-нибудь предложения, как лучше попробовать...поймать...наконец-то форматирование?

Это было полезно?

Решение

На самом деле, это очень хорошо для меня читается.Если ваш реальный код выглядит примерно так, то я бы не стал об этом беспокоиться.ОЧЕНЬ понятно, что происходит.

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

Другие советы

вы можете использовать using блокировать вместо явного Dispose(), иначе вам, вероятно, придется проверить значение null перед его удалением, using блоки сделают это за вас.к сожалению, это увеличивает вложенность =/

try
{
     using(MyService service = new MyService()) 
     {
        service.DoSomething();
        return something;
     }
}
catch (SpecificException ex)
{
     LogSomething(ex);
     return somethingElse;
}
finally
{
     MarkAsComplete();
}

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

try {
  //
} catch(Exception ex) {
  //
} finally {
  //
}

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

Я форматирую код скобками в одной строке:

try {
   MyService service = new Service();
   service.DoSomething();
   return something;
} catch (Exception ex) {
   LogSomething();
   return somethingElse;
} finally {
   MarkAsComplete();
   service.Dispose();
}

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

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

Dear Mr. Container Sir,
Whenever I request from you an instance object of the interface ISomething,
    please construct for me an instance of the concrete class SomethingImpl;
    in addition, please see to it (however you do it) that, whenever I call a
    method on this instance, it is wrapped within a complicated and messy try-
    catch-finally which logs exceptions and mark calls as completed. That way,
    all I have to do is write the business logic that goes into the SomethingImpl
    and I don't have to worry about all the messy infrastuctural details.
Sincerely,
Mr. Agile.

Вы можете увидеть это в коде как:

//a class that knows how to take care of the messy infrastructure details
public class MyMessyInterceptor : IInterceptor {
    public void Intercept(IInvocation invocation) {
        //handle the messy details of continuing with the method-invocation,
        //but within a try-catch-finally that includes exception handling and
        //call logging.
    }
}

//a function that will configure a container (very smart factory)
public IContainer CreateContainer() {
    var builder = new ContainerBuilder();

    //tell the container-builder about the interceptor
    builder
        .Register(c => new MyMessyInterceptor())
        .Named("keep-my-code-clean")
    ;

    //tell the container what to do when you ask it for a ISomething
    builder
        .Register<SomethingImpl>()
        .As<ISomething>()
        .InterceptedBy("keep-my-code-clean")
    ;

    return builder.BuildContainer();
}

//some function out there in your code somewhere that needs to make a
//service call; there's hundreds of functions out there just like this
//in your code, and they all just got much simpler
public object GottaGoDoSomething() {
    //find the container
    var container = GetTheSingletonContainerObject();
    //ask for an instance of ISomething - it knows to provide a
    //SomethingImpl wrapped in an interceptor that takes care of all
    //the logging and exception handling
    var something = container.resolve<ISomething>();
    //call the big method
    return something.DoSomething();
    //magically (not really), the exception handling and logging are
    //already taken care of
}

Создание класса перехватчика происходит только один раз.Регистрация каждого перехватчика и класса обслуживания также происходит только один раз.Настройка контейнера (очень умной фабрики) конечно сложна.

Однако каждое место в вашем коде, которое должно использовать объект службы и встраивать это использование в сложные и запутанные детали инфраструктуры, такие как обработка исключений и ведение журнала, стало очень чистым и очень простым.Здесь только один CreateContainer, но их сотни GottaGoDoSomethings, так что это очень просто за счет некоторой сложности.

(Примечания:В примере кода используется контейнерная платформа Autofac и платформа перехватчика Castle.Я знаю, что это пример шаблона расположения службы, а не шаблона внедрения зависимостей, но целью было проиллюстрировать перехватчики и зарегистрировать их в контейнере, а не проиллюстрировать внедрение зависимостей.)

Пробелы.Как минимум, я всегда помещаю одну строку пробела перед каждым оператором возврата и между разделами кода «выполнение действий» и «создание переменных».

try
{
     MyService service = new Service();

     service.DoSomething();

     return something;

 }
catch (Exception ex)
{
     LogSomething();

     return somethingElse;

}
finally
{
     MarkAsComplete();
     service.Dispose();
}

намного лучше.

Я думаю, что ваше форматирование тоже хорошо читается.Мое предложение состояло бы в том, чтобы использовать только catch заявление скупо.Используйте его только тогда, когда вам действительно нужно что-то поймать.В противном случае вы можете позволить другим частям программы обрабатывать исключение.Вся концепция «раннего провала».

try
{
    //do something that may throw an exception.
}
finally
{
    //handle clean up.
}

//let a method further down the stack handle the exception.

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

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

try { // getting a service

     MyService service = new Service();
     service.DoSomething();

     return something;

}

catch (Exception ex) { // the fact that a service might be full/timedout

     LogSomething();

     return somethingElse;

} 

finally { // remove any resources the service may still hold.

     MarkAsComplete();
     service.Dispose();

}

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

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

Добавлением

// a comment that says what's going on

часто вы можете лучше напомнить себе, что должен делать этот Try.Catch, когда вернетесь к нему через 6 месяцев.

Я всегда пытаюсь провести рефакторинг всех своих блоков try catch и инкапсулировать их в отдельный метод.

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

Если вы действительно хотите избавиться от обязательный но уродливое форматирование (да, я согласен :р)

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

Пытаться ПостШарп или Весна.Нет

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top