posh.wiki


Using "using" - Don't get stuck loading!

2026-06-28

Tags: .NET

Managing loading states is surprisingly difficult. It requires a constant awareness of the potential for a method to exit early, and the discipline to remember to un-set your loading state when you've finished doing work.

Consider, for example, this method, which will leave its class stuck in a loading state forever if it throws:

public void Init() 
{
    IsLoading = true;
    DoWork();
    IsLoading = false;
}

Or this one, where the developer forgot to reset the value (this is a lot more of a problem in complex methods with multiple return paths):

public void Init() 
{
    IsLoading = true;
    DoWork();
    // Forgot IsLoading = false!
}

The safe pattern here, shown below, introduces 8 lines of boilerplate and an ugly level of indentation. It's robust, but sacrifices some readability, and writing it gets old quickly.

public void Init()
{
    IsLoading = true;
    try 
    {
        DoWork();
    }
    finally
    {
        IsLoading = false;
    }
}

So, let me run this pattern by you. For any class that needs loading behaviour, make sure it inherits LoadingBase:

internal abstract class LoadingBase 
{
    public bool IsLoading { get; private set; }

    protected IDisposable UseLoading() => 
        new LoadingDisposable(this);

    private class LoadingDisposable : IDisposable
    {
        private readonly LoadingBase _lb;

        public LoadingDisposable(LoadingBase lb)
        {
            _lb = lb;
            _lb.IsLoading = true;
        }

        public void Dispose() 
        {
            _lb.IsLoading = false;
        }
    }
}

This lets us use the following pattern:

public void Init() 
{
    using var loading = UseLoading();
    DoWork();
}

Which is lowered to:

public void Init() 
{
    IDisposable loading = UseLoading();
    try 
    {
        DoWork();
    }
    finally 
    {
        loading.Dispose();
    }
}

This ensures that IsLoading is set to false no matter when or how the method exits, with only one line. Far less boilerplate than the explicit try/finally pattern!

The one drawback here is that you can't use discard assignment in a using statement. If you do, _ becomes a variable of type IDisposable, much as if it were used as the name of a parameter.