使用大量块?
我想了解您对以下主题的看法:
想象一下,我们有一种方法负责实现一个特定目的,但要做到这一点,它需要大量本地范围对象的支持,其中许多对象实现 IDisposable
。
MS 编码标准规定,当使用不需要在方法范围内“生存”的本地 IDisposable
对象时(不会返回或不会分配给某些寿命较长的 对象的状态信息)
例如)您应该使用 using
构造。
问题是,在某些情况下,您可能会遇到 using
块的嵌套“地狱”:
using (var disposableA = new DisposableObjectA())
{
using (var disposableB = new DisposableObjectB())
{
using (var disposableC = new DisposableObjectC())
{
//And so on, you get the idea.
}
}
}
如果您使用的某些对象派生自公共基础或实现公共 <实现IDisposable
的code>接口。这当然是以每当您需要对象的真实类型时就必须强制转换所述对象为代价的。有时,只要转换量不失控,这就是可行的:
using (var disposableA = new DisposableObjectA())
{
using (DisposableBaseObject disposableB = new DisposableObjectB(),
disposableC = new DisposableObjectC)
{
using (var disposableD = new DisposableObjectD())
{
//And so on, you get the idea.
}
}
}
另一种选择是不使用 using
块并直接实现 try-catch
块。这看起来像:
DisposableObjectA disposableA = null;
DisposableObjectB disposableB = null;
DisposableObjectC disposableC = null;
...
try
{
disposableA = new DisposableObjectA();
....
}
finally
{
if (disposableA != null)
{
disposableA.Dispose();
}
if (disposableB != null)
{
disposableB.Dispose();
}
//and so on
}
有趣的是,VS Code 分析器会将此代码标记为“错误”。它会告诉您并非所有可能的执行路径都确保所有一次性对象在超出范围之前都将被处置。我只能看到这种情况发生,如果某个对象在处理时抛出,在我看来,这永远不应该发生,如果确实发生,通常表明发生了真正混乱的事情,你可能最好像你一样快速而优雅地退出可以从您的整个应用程序。
那么,问题是:您更喜欢哪种方法?无论有多少个嵌套 using
块总是更可取,还是超过一定限制后,最好使用 try-catch
块?
I'd like your opinion on the following subject:
Imagine we have a method that is responsible of achieving one specific purpose, but to do so, it needs the support of an important number of locally scoped objects, many of them implementing IDisposable
.
MS coding standards say that when using local IDisposable
objects that need not "survive" the scope of the method (will not be returned or will not be assigned to the state information of some longer lived object
for instance) you should use the using
construct.
The problem is, that in some situations you can get a nested "hell" of using
blocks:
using (var disposableA = new DisposableObjectA())
{
using (var disposableB = new DisposableObjectB())
{
using (var disposableC = new DisposableObjectC())
{
//And so on, you get the idea.
}
}
}
You can somehow mitigate this if some of the objects you are using derive from a common base or implement a common interface
that implements IDisposable
. This of course comes at a cost of having to cast said objects whenever you need the true type of the object. Sometimes this can be viable as long as the amount of casting doesn't get out of hand:
using (var disposableA = new DisposableObjectA())
{
using (DisposableBaseObject disposableB = new DisposableObjectB(),
disposableC = new DisposableObjectC)
{
using (var disposableD = new DisposableObjectD())
{
//And so on, you get the idea.
}
}
}
The other option is not to use using
blocks and implement directly try-catch
blocks. This would look like:
DisposableObjectA disposableA = null;
DisposableObjectB disposableB = null;
DisposableObjectC disposableC = null;
...
try
{
disposableA = new DisposableObjectA();
....
}
finally
{
if (disposableA != null)
{
disposableA.Dispose();
}
if (disposableB != null)
{
disposableB.Dispose();
}
//and so on
}
Funny thing, is that VS Code Analyzer will flag this code as "wrong". It will inform you that not all possible execution paths ensure that all disposable objects will be disposed before going out of scope. I can only see that happening if some object throws while disposing which in my opinion should never happen, and if it does, its normally a sign that something really messed up is going on and you are probably better of exiting as fast and gracefully as you can from your entire app.
So, the question is: what approach do you like better? Is it always preferable to use nested using
blocks no matter how many, or, past a certain limit, its better to use try-catch
block?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果只有一个语句,则不需要大括号,例如:
但这确实取决于外部块中没有发生任何其他事情。
You don't need the curly brackets if there's just one statement, for example:
This does depend on nothing else happening in the outer blocks though.
我认为您忘记了
using
语句(像许多其他语句一样)不一定需要代码块,但可以是单个语句。你的第一个例子可以写成:我认为这极大地缓解了问题。请注意,如果您需要在调用实现 IDisposable 的实例之间执行某些操作,则没有帮助。
我什至嵌套了其他有意义的块。
foreach
就是一个例子。应该注意的是,当 VS Code 分析器告诉您这是不正确的时,它是正确的:
当您使用彼此堆叠的
using
时,它会将它们嵌套在多个try
中/finally
块,如下所示:在您的示例中,如果执行
disposableA.Dispose
时抛出异常,则disposableB
和disposableC
不会被释放(finally
块退出),如果在调用disposableB
时抛出错误,则disposableC< /code> 未关闭等
I think you are forgetting that the
using
statement (like many others), don't necessarily require a code block, but can be a single statement. Your first example can be written as:I think this eases the problem tremendously. Note, it doesn't help if you need to do something between the invocation of the instances that implement
IDisposable
.I even go so far as to nest other blocks that make sense.
foreach
is an example.It should be noted that VS Code analyzer is correct when it tells you that this is incorrect:
When you use
using
stacked on top of each other, it nests them in multipletry
/finally
blocks, like so:In your example, if there is an exception that is thrown when
disposableA.Dispose
is executed, thendisposableB
anddisposableC
do not get disposed (thefinally
block is exited), if an error is thrown whendisposableB
is called, thendisposableC
is not closed, etc.第一个代码示例的唯一真正“问题”是深层嵌套,这会使阅读和维护代码变得困难。作为建议您简单地删除大括号的其他答案的替代方案,您还可以通过将最深层嵌套的代码重构为单独的函数来解决此问题。这将创建和处理一次性物品的问题与实际使用它们的问题分开了。
The only real 'problem' with your first code sample is the deep nesting, which can make reading and maintaining code hard. As an alternative to the other answers suggesting you simply drop the curly braces, you can also work round this by refactoring the most deeply nested code out into a separate function. This separates the concerns of creating and disposing your disposable objects from actually using them.