我注意到using
最近在我的代码中嵌套语句的级别有所增加。原因可能是因为我使用的pattern越来越多,经常为orasync/await
增加至少一个。using
CancellationTokenSource
CancellationTokenRegistration
那么,如何减少 , 的嵌套using
,让代码看起来不像圣诞树呢?之前在 SO 上也有人问过类似的问题,我想总结一下我从答案中学到的东西。
使用相邻using
没有缩进。一个假的例子:
using (var a = new FileStream())
using (var b = new MemoryStream())
using (var c = new CancellationTokenSource())
{
// ...
}
这可能有效,但通常之间有一些代码using
(例如,创建另一个对象可能为时过早):
// ...
using (var a = new FileStream())
{
// ...
using (var b = new MemoryStream())
{
// ...
using (var c = new CancellationTokenSource())
{
// ...
}
}
}
将相同类型(或强制转换为IDisposable
)的对象组合成单个对象using
,例如:
// ...
FileStream a = null;
MemoryStream b = null;
CancellationTokenSource c = null;
// ...
using (IDisposable a1 = (a = new FileStream()),
b1 = (b = new MemoryStream()),
c1 = (c = new CancellationTokenSource()))
{
// ...
}
这具有与上述相同的限制,而且 IMO 更冗长且可读性更低。
将方法重构为几个方法。
据我了解,这是一种首选方式。然而,我很好奇,为什么以下会被认为是一种不好的做法?
public class DisposableList : List<IDisposable>, IDisposable
{
public void Dispose()
{
base.ForEach((a) => a.Dispose());
base.Clear();
}
}
// ...
using (var disposables = new DisposableList())
{
var a = new FileStream();
disposables.Add(a);
// ...
var b = new MemoryStream();
disposables.Add(b);
// ...
var c = new CancellationTokenSource();
disposables.Add(c);
// ...
}
[更新]注释中有很多有效点,嵌套using
语句确保Dispose
将在每个对象上调用,即使某些内部Dispose
调用抛出。然而,有一个有点模糊的问题:除了最外层的之外,所有可能由处理嵌套的“使用”帧引发的嵌套异常都将丢失。更多关于这个here。