How to create an IAsyncResult that immediately completes?

11k views Asked by At

I am implementing an interface which requires implementations of BeginDoSomething and EndDoSomething methods. However my DoSomething isn't really long-running. For simplicity assume DoSomething only compares two variables and return whether a > b

So my BeginDoSomething should be like:

protected override IAsyncResult BeginDoSomething(int a, int b, AsyncCallback callback, object state)
{
     bool returnValue = a > b;
     return ...; //what should I return here?  
     //The method actually already completed and I don't need to wait for anything
 }

I don't know what I should return. I only implement BeginDoSomething because I have to, not because my method is long-running. Do I need to implement my own IAsyncResult? Is there an implementation already in .NET libraries?

4

There are 4 answers

4
BFree On BEST ANSWER

The quick hack way of doing it is to use a delegate:

protected override IAsyncResult BeginDoSomething(int a, int b, AsyncCallback callback, object state)
{
     bool returnValue = a > b;
     Func<int,int,bool> func = (x,y) => x > y;
     return func.BeginInvoke(a,b,callback,state);
}

The downside of this approach, is that you need to be careful if two threads will be calling this method concurrently you'll get an error.

4
Mike Chamberlain On

This is a little quick and dirty, but you can implement a class that implements IAsyncResult like so:

    public class MyAsyncResult : IAsyncResult
    {
        bool _result;

        public MyAsyncResult(bool result)
        {
            _result = result;
        }

        public bool IsCompleted
        {
            get { return true; }
        }

        public WaitHandle AsyncWaitHandle
        {
            get { throw new NotImplementedException(); }
        }

        public object AsyncState
        {
            get { return _result; }
        }

        public bool CompletedSynchronously
        {
            get { return true; }
        }
    }

Then use it in your BeginDoSomething like this:

    return new MyAsyncResult(a > b);
0
foson On

I'd suggest you follow the directions here to be able to create your implementations using Task based methods in case one of them does turn out to be long running. If DoSomething is short running, you can block on it by creating a Task from its result

public IAsyncResult BeginDoSomething(int a, int b,
                                        AsyncCallback callback,
                                        object state)
{
   return Task.FromResult(DoSomething(a, b)).AsApm(callback, state);
}

public bool EndDoSomething(IAsyncResult asyncResult)
{
   return ((Task<bool>)asyncResult).Result;
}

bool DoSomething(int a, int b)
{
   return a > b;
}

public static IAsyncResult AsApm<T>(this Task<T> task,
                                    AsyncCallback callback,
                                    object state)
{
    if (task == null)
        throw new ArgumentNullException("task");

    var tcs = new TaskCompletionSource<T>(state);
    task.ContinueWith(t =>
                      {
                         if (t.IsFaulted)
                            tcs.TrySetException(t.Exception.InnerExceptions);
                         else if (t.IsCanceled)
                            tcs.TrySetCanceled();
                         else
                            tcs.TrySetResult(t.Result);

                         if (callback != null)
                            callback(tcs.Task);
                      }, TaskScheduler.Default);
    return tcs.Task;
}
0
nawfal On

I am not sure if I am missing something but today you can just return Task.CompletedTask/Task.FromResult. Task implements IAsyncResult

protected override IAsyncResult BeginDoSomething(int a, int b, AsyncCallback callback, object state)
{
     return Task.FromResult(a > b);
}

The IAsyncResult.IsCompleted is rightly true here. The Func.BeginInvoke approach wouldn't result in true.