开发者

How to create an IAsyncResult that immediately completes?

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开发者_StackOverflow中文版 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?


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.


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);


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.


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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜