Форматирование трудно читаемых блоков try..catch..finally? - PullRequest
6 голосов
/ 02 июня 2009

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

Например: </p> <pre><code>try { MyService service = new Service(); service.DoSomething(); return something; } catch (Exception ex) { LogSomething(); return somethingElse; } finally { MarkAsComplete(); service.Dispose(); }

Эти 7 строк кода превратились в 16-строчный беспорядок.

Любые предложения по лучшей попытке .. поймать .. окончательное форматирование?

Ответы [ 11 ]

6 голосов
/ 02 июня 2009

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

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

5 голосов
/ 16 июля 2009

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

try
{
     using(MyService service = new MyService()) 
     {
        service.DoSomething();
        return something;
     }
}
catch (SpecificException ex)
{
     LogSomething(ex);
     return somethingElse;
}
finally
{
     MarkAsComplete();
}
4 голосов
/ 02 июня 2009

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

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

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

2 голосов
/ 02 июня 2009

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

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, но есть сотни GottaGoDoSomething с, так что это очень легко за счет немного сложного.

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

2 голосов
/ 02 июня 2009

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

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

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

1 голос
/ 02 июня 2009

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

try
{
     MyService service = new Service();

     service.DoSomething();

     return something;

 }
catch (Exception ex)
{
     LogSomething();

     return somethingElse;

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

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

0 голосов
/ 03 июня 2015

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

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

Попробуйте PostSharp или Spring.Net

0 голосов
/ 15 сентября 2009

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

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

0 голосов
/ 02 июня 2009

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

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

Добавляя

// a comment that says what's going on

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

0 голосов
/ 02 июня 2009

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

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

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();

}
...