Я заметил, что уровень вложенных операторов using
в последнее время увеличился в моем коде. Причина, вероятно, связана с тем, что я использую все больше шаблонов async/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);
// ...
}
[UPDATE] В комментариях имеется немало действительных точек, которые вставляют инструкции using
, чтобы Dispose
вызывался на каждый объект, даже если некоторые внутренние вызовы Dispose
, Тем не менее, существует несколько неясная проблема: все вложенные исключения, которые могут быть сброшены путем размещения вложенных "используемых" кадров, будут потеряны, кроме самого внешнего. Подробнее об этом здесь.