Я заметил, что уровень вложенных операторов 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, Тем не менее, существует несколько неясная проблема: все вложенные исключения, которые могут быть сброшены путем размещения вложенных "используемых" кадров, будут потеряны, кроме самого внешнего. Подробнее об этом здесь.
