3
\$\begingroup\$

I've made this extension method. Its purpose is to trigger the disposal of a value, stored in a Nito.AsyncEx AsyncLazy, as authored by @StephenCleary.

Is this an approach that makes sense? Is the code good?

using System;
using System.Threading.Tasks;

using Nito.AsyncEx;

/// <summary>
/// Extensions to types in the <see cref="Nito.AsyncEx"> namespace.
/// </summary>
public static class NitoAsyncEx
{
    /// <summary>
    /// Disposes the specified <see cref="AsyncLazy"> value.
    /// </summary>
    /// <typeparam name="T">The type of the lazy value.</typeparam>
    /// <param name="asyncLazy> The asynchronous lazy.</param>
    /// <returns>When disposal is complete.</returns>
    public static async Task Dispose<T>(
            this AsyncLazy<T> asyncLazy) where T : IDisposable
    {
        if (asyncLazy.Id != 0)
        {
            (await asyncLazy).Dispose();
        }
    }
}
\$\endgroup\$
4
\$\begingroup\$

It's potentially dangerous to only conditionally dispose of the resource. If you don't dispose it if the resource was never initialized in the first place then you run the risk of some code actually initializing it later, and then not disposing of that resource.

The safer design would be to wrap the object, rather than just having this one extension method.

public class DisposableAsyncLazy<T> : IDisposable
    where T : IDisposable
{
    private AsyncLazy<T> lazy;
    private bool disposed = false;
    public DisposableAsyncLazy(Func<T> factory)
    {
        lazy = new AsyncLazy<T>(factory);
    }
    public DisposableAsyncLazy(Func<Task<T>> factory)
    {
        lazy = new AsyncLazy<T>(factory);
    }
    public int Id
    {
        get
        {
            return lazy.Id;
        }
    }
    public async Task<T> GetValue()
    {
        if (!disposed)
            return await lazy;
        else
            throw new ObjectDisposedException("DisposableAsyncLazy");
    }
    public void Start()
    {
        if (!disposed)
            lazy.Start();
        else
            throw new ObjectDisposedException("DisposableAsyncLazy");
    }

    public async void Dispose()
    {
        disposed = true;
        if (lazy.Id != 0)
            (await lazy).Dispose();

    }
}

(Note you can make DisposableAsyncLazy awaitable, rather than having a method/property produce a task, if you want to take the time to do so.)

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ +1, the only downside I see, is that this will mask the debugger help built into Nito.AsyncEx.AsyncLazy which is non trivial, for me at least, to add to a composition external to the Nito.AsyncEx assembly. (The [DebuggerDisplay] stuff). nitoasyncex.codeplex.com/SourceControl/latest#Source/… \$\endgroup\$ – Jodrell Sep 5 '14 at 8:40
  • \$\begingroup\$ @Jodrell That's the upside of open source content. You actually can put this type inside the same assembly as the type it's composing, if you're willing to re-compile the assembly. That said, I'm not particularly familiar with that feature, so I couldn't say if there's a better option. \$\endgroup\$ – Servy Sep 5 '14 at 13:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.