5

你是如何格式化你的try..catch.finally块的?尤其是当只将它包装在少量代码上时,它会破坏一切,使代码在我看来非常不可读和难看。

如:

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

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

关于更好的try..catch..finally格式的任何建议?

4

11 回答 11

6

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

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

于 2009-06-02T00:32:57.550 回答
5

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

try
{
     using(MyService service = new MyService()) 
     {
        service.DoSomething();
        return something;
     }
}
catch (SpecificException ex)
{
     LogSomething(ex);
     return somethingElse;
}
finally
{
     MarkAsComplete();
}
于 2009-07-15T22:30:58.920 回答
4

嗯,我认为这很好。其中一些进入了大括号放置辩论。你可以这样做:

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

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

于 2009-06-02T00:31:36.977 回答
2

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

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

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

于 2009-06-02T00:32:03.793 回答
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 拦截器框架。我知道这是服务定位模式的示例,而不是依赖注入模式,但重点是说明拦截器并将它们注册到一个容器,不是为了说明依赖注入。)

于 2009-06-02T01:04:31.963 回答
1

空白。作为最低要求,我总是在每个 return 语句之前以及代码的“做事”和“创建变量”部分之间放置一行空格。

try
{
     MyService service = new Service();

     service.DoSomething();

     return something;

 }
catch (Exception ex)
{
     LogSomething();

     return somethingElse;

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

好多了。

于 2009-06-02T00:29:58.413 回答
0

我认为你的格式也很好读。我的建议是仅catch谨慎使用该语句。仅在您确实需要捕获某些东西时才使用它。否则,您可以让程序的其他部分处理异常。整个“早期失败”的概念。

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

//let a method further down the stack handle the exception.
于 2009-06-02T00:48:33.073 回答
0

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

我有一个宽屏,我打开它的一侧,所以空白可以让各个列很好地排列,并且不会对我造成太大伤害,因为我有这么多的屏幕空间......

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

}
于 2009-06-02T01:02:30.207 回答
0

我也喜欢你原来的。.cs 文件中的物理行不会花费您任何费用,也不会更改最终输出代码。因此,请使用您需要的所有内容,以便为您或您的团队提供最佳的可读性。

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

通过增加

// a comment that says what's going on

通常,当您在 6 个月后重新使用该 Try.Catch 时,您可以更好地提醒自己该做什么。

于 2009-06-02T01:14:22.537 回答
0

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

这似乎总是让一切都更具可读性,而且让你的方法只做一件事是一种很好的编程实践。奇怪的是,如果您在 try-catch-finally 语句的上方和下方都有代码,那么您所做的不止一件事。

于 2009-09-15T18:05:06.227 回答
0

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

Aspect Oriented Programming,你会得到 try...catch...finally 免费嵌入到你的程序集中并自动记录异常。

试试PostSharpSpring.Net

于 2015-06-03T18:35:25.593 回答