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;
}
精彩评论