Search code examples
c#concurrencyasynchronousiasyncresult

Implementing IAsyncResult explicitly


I am generally wary of implementing interfaces partially. However, IAsyncResult is a bit of a special case, given that it supports several quite different usage patterns. How often do you use/see used the AsyncState/AsyncCallback pattern, as opposed to just calling EndInvoke, using AsyncWaitHandle, or polling IsCompleted (yuck)?

Related question: Detecting that a ThreadPool WorkItem has completed/waiting for completion.

Consider this class (very approximate, locking needed):

public class Concurrent<T> {
    private ManualResetEvent _resetEvent;
    private T _result;

    public Concurrent(Func<T> f) {
        ThreadPool.QueueUserWorkItem(_ => {
                                         _result = f();
                                         IsCompleted = true;
                                         if (_resetEvent != null)
                                             _resetEvent.Set();
                                     });
    }

    public WaitHandle WaitHandle {
        get {
            if (_resetEvent == null)
                _resetEvent = new ManualResetEvent(IsCompleted);
            return _resetEvent;
        }

    public bool IsCompleted {get; private set;}
    ...

It has WaitHandle (lazily created, just as described in IAsyncResult documentation) and IsCompleted, but I don't see a sensible implementation for AsyncState ({return null;}?). So does it make sense for it to implement IAsyncResult? Note that Task in the Parallel Extensions library does implement IAsyncResult, but only IsCompleted is implemented implicitly.


Solution

    • In my experience, just calling EndInvoke without either waiting or being called back first is rarely useful
    • Just providing callbacks is sometimes not enough, as your clients might want to wait for multiple operations at once (WaitAny, WaitAll)
    • I've never polled IsCompleted, yuck indeed! So, you could save the implementation of IsCompleted, but it's so simple that it doesn't seem to be worth to potentially astonish your clients.

    So, a reasonable implementation for an asynchronously callable method should really provide a fully implemented IAsyncResult.

    BTW, you often don't need to implement IAsyncResult yourself, just return what is returned by Delegate.BeginInvoke. See the implementation of System.IO.Stream.BeginRead for an example.