难以阅读的格式化try..catch..finally块?

时间:2009-06-02 00:27:39

标签: c# formatting try-catch-finally

你如何格式化try..catch.finally块?特别是当它只围绕少量代码包装时,它会使所有内容破坏,并且在我看来代码变得难以理解和不雅观。

如:

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

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

这7行代码变成了16行混乱。

有关更好的try..catch ..最终格式化的任何建议吗?

11 个答案:

答案 0 :(得分:6)

实际上,这对我来说非常好。如果您的实际代码看起来很像这样,那么我真的不会担心它。发生的事情非常清楚。

如果您的实际代码更复杂,那么请考虑将这些块分解为命名良好的方法。

答案 1 :(得分:5)

您可以使用using块而不是显式Dispose(),否则您在处置它之前必须检查null,using块会为您执行此操作。不幸的是它确实增加了嵌套= /

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

答案 2 :(得分:4)

嗯,我觉得这很好。其中一些涉及到大括号放置辩论。你可以这样做:

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

我更喜欢你拥有的东西。但是,您可能需要考虑将代码修改为只有一个return语句。我发现这是一个更好的设计。

答案 3 :(得分:2)

我用同一行的括号格式化代码:

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

如果我想要更多间距,我更喜欢添加空行。这也可以作为逻辑代码块之间的分隔符。

答案 4 :(得分:2)

您可能会考虑容器(非常聪明的工厂)和建议(处理所有混乱的细节)。

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拦截器框架。我知道这是服务位置模式的一个示例,而不是依赖注入模式,但重点是说明拦截器和使用容器注册它们,而不是说明依赖注入。)

答案 5 :(得分:1)

空白。作为最低限度,我总是在每个return语句之前和“执行内容”和“创建变量”代码段之间放置一行空格。

try
{
     MyService service = new Service();

     service.DoSomething();

     return something;

 }
catch (Exception ex)
{
     LogSomething();

     return somethingElse;

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

好多了。

答案 6 :(得分:0)

我认为你的格式也很好。我的建议是只谨慎使用catch声明。只有在你真正需要捕捉的东西时才使用它。否则,您可以让程序的其他部分处理异常。整个“早期失败”的概念。

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

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

答案 7 :(得分:0)

就个人而言,我倾向于在我的代码中遵循上述风格......它提供了发表评论的空间,并更好地展示了我的逻辑流程。

我有一个宽屏幕,我打开它的侧面,所以空白允许各个列排好并且不会伤害我那么多,因为我有这么多的屏幕空间,因为它...... / p>

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

}

答案 8 :(得分:0)

我也是,就像你原来的一样。 .cs文件中的物理行不会花费任何成本,也不会更改最终输出代码。因此,请使用您所需的一切,以便为您或您的团队提供最佳的可读性。

事实上,当您编码时,您应该尝试使用比您在此处显示的16行更多的行,方法是为自己或他人添加注释。

添加

// a comment that says what's going on

经常,您可以更好地提醒自己,当您在6个月后返回时,Try.Catch应该做什么。

答案 9 :(得分:0)

我总是尝试重构我的所有try catch块并将它们封装在自己的方法中。

这似乎总是让所有东西都更具可读性,而且这是一个很好的编程习惯,让你的方法只做一件事。可能的情况是,如果你的代码高于和低于你的try-catch-finally语句,那么你做的不止一件事。

答案 10 :(得分:0)

如果你真的想摆脱强制性丑陋的格式(是的,我同意:p)

选择面向方面编程,最后您将获得try ... catch ... 在程序集中免费嵌入并自动记录异常。

尝试PostSharpSpring.Net