How to make an Asynchronous Method return a value?

I know how to make Async methods but say I have a method that does a lot of work then returns a boolean value?

How do I return the boolean value on the callback?

Clarification:

public bool Foo(){
Thread.Sleep(100000); // Do work
return true;
}

I want to be able to make this asynchronous.

153402 次浏览

Use a BackgroundWorker. It will allow you to get callbacks on completion and allow you to track progress. You can set the Result value on the event arguments to the resulting value.

    public void UseBackgroundWorker()
{
var worker = new BackgroundWorker();
worker.DoWork += DoWork;
worker.RunWorkerCompleted += WorkDone;
worker.RunWorkerAsync("input");
}


public void DoWork(object sender, DoWorkEventArgs e)
{
e.Result = e.Argument.Equals("input");
Thread.Sleep(1000);
}


public void WorkDone(object sender, RunWorkerCompletedEventArgs e)
{
var result = (bool) e.Result;
}

There are a few ways of doing that... the simplest is to have the async method also do the follow-on operation. Another popular approach is to pass in a callback, i.e.

void RunFooAsync(..., Action<bool> callback) {
// do some stuff
bool result = ...


if(callback != null) callback(result);
}

Another approach would be to raise an event (with the result in the event-args data) when the async operation is complete.

Also, if you are using the TPL, you can use ContinueWith:

Task<bool> outerTask = ...;
outerTask.ContinueWith(task =>
{
bool result = task.Result;
// do something with that
});

You should use the EndXXX of your async method to return the value. EndXXX should wait until there is a result using the IAsyncResult's WaitHandle and than return with the value.

From C# 5.0, you can specify the method as

public async Task<bool> doAsyncOperation()
{
// do work
return true;
}


bool result = await doAsyncOperation();

Probably the simplest way to do it is to create a delegate and then BeginInvoke, followed by a wait at some time in the future, and an EndInvoke.

public bool Foo(){
Thread.Sleep(100000); // Do work
return true;
}


public SomeMethod()
{
var fooCaller = new Func<bool>(Foo);
// Call the method asynchronously
var asyncResult = fooCaller.BeginInvoke(null, null);


// Potentially do other work while the asynchronous method is executing.


// Finally, wait for result
asyncResult.AsyncWaitHandle.WaitOne();
bool fooResult = fooCaller.EndInvoke(asyncResult);


Console.WriteLine("Foo returned {0}", fooResult);
}

Perhaps you can try to BeginInvoke a delegate pointing to your method like so:




delegate string SynchOperation(string value);


class Program
{
static void Main(string[] args)
{
BeginTheSynchronousOperation(CallbackOperation, "my value");
Console.ReadLine();
}


static void BeginTheSynchronousOperation(AsyncCallback callback, string value)
{
SynchOperation op = new SynchOperation(SynchronousOperation);
op.BeginInvoke(value, callback, op);
}


static string SynchronousOperation(string value)
{
Thread.Sleep(10000);
return value;
}


static void CallbackOperation(IAsyncResult result)
{
// get your delegate
var ar = result.AsyncState as SynchOperation;
// end invoke and get value
var returned = ar.EndInvoke(result);


Console.WriteLine(returned);
}
}

Then use the value in the method you sent as AsyncCallback to continue..