Search code examples
c#asp.netusing

Create using blocks for multiple objects in collection


Given the following code:

using (payment.GetModifyLock())
{
    foreach (var paymentItem in paymentItems)
    {
        using (paymentItem.GetModifyLock())
        {
            
        }
    }
    DoAction();
}

I'm looking to modify this code so that DoAction is done inside all the using blocks (not just one). If the collection contains two items, I'd want it to function in this way:

using(payment.GetModifyLock())
using(paymentItem1.GetModifyLock())
using(paymentItem2.GetModifyLock())
{
    DoAction();
}

Is this possible?


Solution

  • If you wanted to create a more reusable version of what you have, you can wrap the functionality into an IDisposable helper class. This is naïve and not recommended for production code, but it is a simple, reusable abstraction.

    public class NestedLocker : IDisposable
    {
        private readonly IDisposable _parentLocker;
        private readonly Queue<IDisposable> _childLockers = new Queue<IDisposable>();
        
        public NestedLocker(Func<IDisposable> parentLocker, 
            IEnumerable<Func<IDisposable>> childLockers)
        {
            _parentLocker = parentLocker();
            
            foreach (var childLocker in childLockers)
            {
                _childLockers.Enqueue(childLocker());
            }
        }
    
        public void Dispose()
        {
            foreach (var childLocker in _childLockers)
            {
                childLocker.Dispose();
            }
            
            _parentLocker.Dispose();
        }
    }
    

    You can test it with the following:

    void Main()
    {
        Func<IDisposable> parentLocker = () => new ParentLocker();
        List<Func<IDisposable>> childLockers = 
            new List<Func<IDisposable>> { () => new ChildLocker(), () => new ChildLocker() };
        using (new NestedLocker(parentLocker, childLockers))
        {
            Console.WriteLine("action");
        }
    }
    
    public class ParentLocker : IDisposable
    {
        public ParentLocker()
        {
            Console.WriteLine("Parent locker created");
        }
        
        public void Dispose()
        {
            Console.WriteLine("Parent locker disposed");
        }
    }
    
    public class ChildLocker : IDisposable
    {
        public ChildLocker()
        {
            Console.WriteLine("Child locker created");
        }
        
        public void Dispose()
        {
            Console.WriteLine("Child locker disposed");
        }
    }
    

    which outputs:

    Parent locker created
    Child locker created
    Child locker created
    action
    Child locker disposed
    Child locker disposed
    Parent locker disposed