执行嵌套 TRY / FINALLY 语句的最佳实践
嗨,进行嵌套尝试的最佳方法是什么? 最后在delphi中声明?
var cds1 : TClientDataSet;
cds2 : TClientDataSet;
cds3 : TClientDataSet;
cds4 : TClientDataSet;
begin
cds1 := TClientDataSet.Create(application );
try
cds2 := TClientDataSet.Create(application );
try
cds3 := TClientDataSet.Create(application );
try
cds4 := TClientDataSet.Create(application );
try
///////////////////////////////////////////////////////////////////////
/// DO WHAT NEEDS TO BE DONE
///////////////////////////////////////////////////////////////////////
finally
cds4.free;
end;
finally
cds3.free;
end;
finally
cds2.free;
end;
finally
cds1.free;
end;
end;
你能建议一个更好的方法吗?
Hi What is the best way to do nested try & finally statements in delphi?
var cds1 : TClientDataSet;
cds2 : TClientDataSet;
cds3 : TClientDataSet;
cds4 : TClientDataSet;
begin
cds1 := TClientDataSet.Create(application );
try
cds2 := TClientDataSet.Create(application );
try
cds3 := TClientDataSet.Create(application );
try
cds4 := TClientDataSet.Create(application );
try
///////////////////////////////////////////////////////////////////////
/// DO WHAT NEEDS TO BE DONE
///////////////////////////////////////////////////////////////////////
finally
cds4.free;
end;
finally
cds3.free;
end;
finally
cds2.free;
end;
finally
cds1.free;
end;
end;
Can you Suggest a better way of doing this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
下面怎么样:
这使其保持紧凑,并且仅尝试释放已创建的实例。 实际上没有必要执行嵌套,因为任何失败都会导致放弃到最后并执行您提供的示例中的所有清理。
就我个人而言,我尽量不要嵌套在同一个方法中......但 try/try/ except/finally 场景除外。 如果我发现自己需要嵌套,那么对我来说,这是考虑重构到另一个方法调用的好时机。
编辑由于mghie和utku。
编辑将对象创建更改为不引用应用程序,因为在本示例中没有必要。
how about the following:
This keeps it compact, and only attempts to free the instances which were created. There really is no need to perform the nesting since ANY failure will result in dropping to the finally and performing all of the cleanup in the example you provided.
Personally I try not to nest within the same method... with the exception being a try/try/except/finally scenario. If I find myself needing to nest, then to me that is a great time to think refactoring into another method call.
EDIT Cleaned up a bit thanks to the comments by mghie and utku.
EDIT changed the object creation to not reference application, as its not necessary in this example.
我会使用这样的东西:
有关接口的实现,请参阅这篇文章,但您可以轻松地自己创建类似的东西。
编辑:
我刚刚注意到链接文章中的 Guard() 是一个过程。 在我自己的代码中,我重载了返回 TObject 的 Guard() 函数,上面的示例代码假设了类似的情况。 当然,使用泛型现在可以编写更好的代码...
编辑2:
如果您想知道为什么 try ...finally 在我的代码中被完全删除:在不引入可能性的情况下删除嵌套块是不可能的内存泄漏(当析构函数引发异常时)或访问冲突。 因此,最好使用辅助类,并让接口的引用计数完全接管。 即使某些析构函数引发异常,辅助类也可以释放它所保护的所有对象。
I'd use something like this:
For the implementation of the interface see this article, but you can easily create something similar yourself.
EDIT:
I just noticed that in the linked article Guard() is a procedure. In my own code I have overloaded Guard() functions that return TObject, above sample code assumes something similar. Of course with generics much better code is now possible...
EDIT 2:
If you wonder why try ... finally is completely removed in my code: It's impossible to remove the nested blocks without introducing the possibility of memory leaks (when destructors raise exceptions) or access violations. Therefore it's best to use a helper class, and let the reference counting of interfaces take over completely. The helper class can free all objects it guards, even if some of the destructors raise exceptions.
没有嵌套尝试的代码还有另一种变体...最后我才想到。 如果您不将构造函数的 AOwner 参数设置为 nil 来创建组件,那么您可以简单地利用 VCL 免费提供的生命周期管理:
我是小代码的忠实拥护者(如果不是)太混乱了)。
There's another variation of the code without nested try ... finally that just occurred to me. If you don't create the components with the AOwner parameter of the constructor set to nil, then you can simply make use of the lifetime management that the VCL gives you for free:
I'm a big believer in small code (if it's not too obfuscated).
如果你想走这条(IMO)丑陋的路线(将初始化设置为 nil 的组处理以了解是否需要释放),你至少必须保证你不会让析构函数之一中的异常阻止释放其余的你的对象。
就像是:
If you want to go this (IMO) ugly route (group handling with initialization to nil to know if freeing is needed), you at least MUST guarantee that you won't let an exception in one of the destructor prevent from freeing the rest of your objects.
Something like:
有一个关于构造函数中的异常的精彩视频 析构函数
它显示了一些很好的示例,例如:
如果 cds2 的析构函数中出现错误,会发生什么
Cds1 将不会被销毁
编辑
另一个很好的资源是:
Jim McKeeth 关于 代码范围 III 中的延迟异常处理,他谈到了在 finally 块中处理异常的问题。
There is a good video on exceptions in constructors & destructors
It shows some nice examples such as:
What has if there in an error in the destructor of cds2
Cds1 will not be Destroyed
EDIT
Another good resource is :
Jim McKeeth excellent video on Delayed Exception Handling in code range III were he talks about problems in handling exceptions in the finally block.
@mghie:Delphi 有堆栈分配的对象:
不幸的是,如上面的示例所示:堆栈分配的对象不能防止内存泄漏。
因此,这仍然需要像这样调用析构函数:
好吧,我承认,这几乎是偏离主题的,但我认为在这种情况下可能会很有趣,因为提到了堆栈分配对象作为解决方案(它们不是如果没有自动析构函数调用)。
@mghie: Delphi has got stack allocated objects:
Unfortunately, as the above example shows: Stack allocated objects do not prevent memory leaks.
So this would still require a call to the destructor like this:
OK, I admit it, this is very nearly off topic, but I thought it might be interesting in this context since stack allocated objects were mentioned as a solution (which they are not if there is no automatic destructor call).