你如何格式化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 ..最终格式化的任何建议吗?
答案 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 ... 在程序集中免费嵌入并自动记录异常。